aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/.clang-format5
-rw-r--r--src/Makefile.am51
-rw-r--r--src/Makefile.bench.include14
-rw-r--r--src/Makefile.leveldb.include12
-rw-r--r--src/Makefile.qt.include5
-rw-r--r--src/Makefile.qttest.include23
-rw-r--r--src/Makefile.test.include78
-rw-r--r--src/addrdb.cpp220
-rw-r--r--src/addrdb.h12
-rw-r--r--src/addrman.cpp25
-rw-r--r--src/addrman.h29
-rw-r--r--src/amount.h45
-rw-r--r--src/arith_uint256.cpp8
-rw-r--r--src/arith_uint256.h14
-rw-r--r--src/base58.cpp199
-rw-r--r--src/base58.h38
-rw-r--r--src/bech32.cpp191
-rw-r--r--src/bech32.h25
-rw-r--r--src/bench/base58.cpp27
-rw-r--r--src/bench/bench.cpp28
-rw-r--r--src/bench/bench.h13
-rw-r--r--src/bench/bench_bitcoin.cpp4
-rw-r--r--src/bench/ccoins_caching.cpp4
-rw-r--r--src/bench/checkblock.cpp10
-rw-r--r--src/bench/checkqueue.cpp103
-rw-r--r--src/bench/coin_selection.cpp7
-rw-r--r--src/bench/crypto_hash.cpp27
-rw-r--r--src/bench/lockedpool.cpp8
-rw-r--r--src/bench/mempool_eviction.cpp7
-rw-r--r--src/bench/perf.cpp2
-rw-r--r--src/bench/prevector_destructor.cpp36
-rw-r--r--src/bench/verify_script.cpp10
-rw-r--r--src/bitcoin-cli.cpp209
-rw-r--r--src/bitcoin-tx.cpp142
-rw-r--r--src/bitcoind.cpp55
-rw-r--r--src/blockencodings.cpp50
-rw-r--r--src/blockencodings.h13
-rw-r--r--src/bloom.cpp43
-rw-r--r--src/bloom.h8
-rw-r--r--src/chain.cpp35
-rw-r--r--src/chain.h59
-rw-r--r--src/chainparams.cpp143
-rw-r--r--src/chainparams.h27
-rw-r--r--src/chainparamsbase.cpp30
-rw-r--r--src/chainparamsbase.h16
-rw-r--r--src/chainparamsseeds.h2263
-rw-r--r--src/checkpoints.cpp6
-rw-r--r--src/checkqueue.h40
-rw-r--r--src/clientversion.cpp2
-rw-r--r--src/clientversion.h26
-rw-r--r--src/coins.cpp280
-rw-r--r--src/coins.h399
-rw-r--r--src/compat.h13
-rw-r--r--src/compat/byteswap.h2
-rw-r--r--src/compat/endian.h4
-rw-r--r--src/compat/glibc_sanity.cpp2
-rw-r--r--src/compat/glibcxx_sanity.cpp2
-rw-r--r--src/compressor.cpp8
-rw-r--r--src/compressor.h4
-rw-r--r--src/consensus/consensus.h8
-rw-r--r--src/consensus/merkle.cpp4
-rw-r--r--src/consensus/merkle.h6
-rw-r--r--src/consensus/params.h2
-rw-r--r--src/consensus/tx_verify.cpp250
-rw-r--r--src/consensus/tx_verify.h78
-rw-r--r--src/consensus/validation.h19
-rw-r--r--src/core_io.h5
-rw-r--r--src/core_memusage.h7
-rw-r--r--src/core_read.cpp62
-rw-r--r--src/core_write.cpp79
-rw-r--r--src/crypto/aes.cpp3
-rw-r--r--src/crypto/aes.h8
-rw-r--r--src/crypto/chacha20.cpp180
-rw-r--r--src/crypto/chacha20.h26
-rw-r--r--src/crypto/common.h59
-rw-r--r--src/crypto/hmac_sha256.h2
-rw-r--r--src/crypto/sha256.cpp236
-rw-r--r--src/crypto/sha256.h6
-rw-r--r--src/crypto/sha256_sse4.cpp1506
-rw-r--r--src/cuckoocache.h76
-rw-r--r--src/dbwrapper.cpp89
-rw-r--r--src/dbwrapper.h75
-rw-r--r--src/fs.cpp15
-rw-r--r--src/fs.h24
-rw-r--r--src/hash.cpp84
-rw-r--r--src/hash.h58
-rw-r--r--src/httprpc.cpp84
-rw-r--r--src/httprpc.h2
-rw-r--r--src/httpserver.cpp185
-rw-r--r--src/httpserver.h12
-rw-r--r--src/init.cpp940
-rw-r--r--src/init.h16
-rw-r--r--src/key.cpp30
-rw-r--r--src/key.h12
-rw-r--r--src/keystore.cpp2
-rw-r--r--src/keystore.h41
-rw-r--r--src/leveldb/Makefile12
-rw-r--r--src/leveldb/README.md25
-rwxr-xr-xsrc/leveldb/build_detect_platform30
-rw-r--r--src/leveldb/db/db_bench.cc38
-rw-r--r--src/leveldb/db/db_impl.cc1
-rw-r--r--src/leveldb/db/log_format.h2
-rw-r--r--src/leveldb/db/memtable.cc2
-rw-r--r--src/leveldb/db/version_set.cc57
-rw-r--r--src/leveldb/db/version_set.h4
-rw-r--r--src/leveldb/doc/doc.css89
-rw-r--r--src/leveldb/doc/impl.html213
-rw-r--r--src/leveldb/doc/impl.md170
-rw-r--r--src/leveldb/doc/index.html549
-rw-r--r--src/leveldb/doc/index.md523
-rw-r--r--src/leveldb/doc/log_format.md75
-rw-r--r--src/leveldb/doc/log_format.txt75
-rw-r--r--src/leveldb/doc/table_format.md107
-rw-r--r--src/leveldb/doc/table_format.txt104
-rw-r--r--src/leveldb/include/leveldb/db.h2
-rw-r--r--src/leveldb/include/leveldb/options.h12
-rw-r--r--src/leveldb/port/atomic_pointer.h47
-rw-r--r--src/leveldb/port/port_example.h10
-rw-r--r--src/leveldb/port/port_posix.cc14
-rw-r--r--src/leveldb/port/port_posix.h3
-rw-r--r--src/leveldb/port/port_posix_sse.cc110
-rw-r--r--src/leveldb/port/port_win.cc11
-rw-r--r--src/leveldb/port/port_win.h3
-rw-r--r--src/leveldb/table/filter_block.cc2
-rw-r--r--src/leveldb/util/crc32c.cc22
-rw-r--r--src/leveldb/util/env_posix.cc195
-rw-r--r--src/leveldb/util/env_posix_test.cc66
-rw-r--r--src/leveldb/util/env_posix_test_helper.h28
-rw-r--r--src/leveldb/util/env_test.cc18
-rw-r--r--src/leveldb/util/env_win.cc12
-rw-r--r--src/leveldb/util/logging.cc2
-rw-r--r--src/leveldb/util/options.cc1
-rw-r--r--src/limitedmap.h2
-rw-r--r--src/memusage.h17
-rw-r--r--src/merkleblock.cpp46
-rw-r--r--src/merkleblock.h22
-rw-r--r--src/miner.cpp306
-rw-r--r--src/miner.h51
-rw-r--r--src/net.cpp965
-rw-r--r--src/net.h261
-rw-r--r--src/net_processing.cpp1257
-rw-r--r--src/net_processing.h54
-rw-r--r--src/netaddress.cpp65
-rw-r--r--src/netaddress.h22
-rw-r--r--src/netbase.cpp296
-rw-r--r--src/netbase.h12
-rw-r--r--src/netmessagemaker.h6
-rw-r--r--src/policy/feerate.cpp (renamed from src/amount.cpp)2
-rw-r--r--src/policy/feerate.h59
-rw-r--r--src/policy/fees.cpp894
-rw-r--r--src/policy/fees.h354
-rw-r--r--src/policy/policy.cpp87
-rw-r--r--src/policy/policy.h16
-rw-r--r--src/policy/rbf.cpp4
-rw-r--r--src/policy/rbf.h2
-rw-r--r--src/pow.cpp5
-rw-r--r--src/prevector.h41
-rw-r--r--src/primitives/block.cpp14
-rw-r--r--src/primitives/block.h8
-rw-r--r--src/primitives/transaction.cpp61
-rw-r--r--src/primitives/transaction.h61
-rw-r--r--src/protocol.cpp8
-rw-r--r--src/protocol.h4
-rw-r--r--src/pubkey.cpp21
-rw-r--r--src/pubkey.h4
-rw-r--r--src/qt/addressbookpage.cpp4
-rw-r--r--src/qt/addressbookpage.h2
-rw-r--r--src/qt/addresstablemodel.cpp25
-rw-r--r--src/qt/bantablemodel.cpp6
-rw-r--r--src/qt/bitcoin.cpp149
-rw-r--r--src/qt/bitcoinaddressvalidator.cpp6
-rw-r--r--src/qt/bitcoingui.cpp45
-rw-r--r--src/qt/bitcoingui.h6
-rw-r--r--src/qt/bitcoinstrings.cpp71
-rw-r--r--src/qt/callback.h30
-rw-r--r--src/qt/clientmodel.cpp40
-rw-r--r--src/qt/clientmodel.h11
-rw-r--r--src/qt/coincontroldialog.cpp70
-rw-r--r--src/qt/coincontroldialog.h7
-rw-r--r--src/qt/coincontroltreewidget.cpp5
-rw-r--r--src/qt/forms/debugwindow.ui2
-rw-r--r--src/qt/forms/intro.ui35
-rw-r--r--src/qt/forms/optionsdialog.ui120
-rw-r--r--src/qt/forms/sendcoinsdialog.ui124
-rw-r--r--src/qt/guiutil.cpp178
-rw-r--r--src/qt/guiutil.h17
-rw-r--r--src/qt/intro.cpp50
-rw-r--r--src/qt/locale/bitcoin_af.ts110
-rw-r--r--src/qt/locale/bitcoin_af_ZA.ts84
-rw-r--r--src/qt/locale/bitcoin_ar.ts34
-rw-r--r--src/qt/locale/bitcoin_be_BY.ts4
-rw-r--r--src/qt/locale/bitcoin_bg.ts28
-rw-r--r--src/qt/locale/bitcoin_ca.ts8
-rw-r--r--src/qt/locale/bitcoin_ca@valencia.ts4
-rw-r--r--src/qt/locale/bitcoin_ca_ES.ts38
-rw-r--r--src/qt/locale/bitcoin_cs.ts44
-rw-r--r--src/qt/locale/bitcoin_da.ts36
-rw-r--r--src/qt/locale/bitcoin_de.ts152
-rw-r--r--src/qt/locale/bitcoin_el_GR.ts278
-rw-r--r--src/qt/locale/bitcoin_en.ts687
-rw-r--r--src/qt/locale/bitcoin_en_GB.ts8
-rw-r--r--src/qt/locale/bitcoin_eo.ts126
-rw-r--r--src/qt/locale/bitcoin_es.ts187
-rw-r--r--src/qt/locale/bitcoin_es_DO.ts4
-rw-r--r--src/qt/locale/bitcoin_es_ES.ts100
-rw-r--r--src/qt/locale/bitcoin_es_MX.ts8
-rw-r--r--src/qt/locale/bitcoin_et.ts32
-rw-r--r--src/qt/locale/bitcoin_et_EE.ts32
-rw-r--r--src/qt/locale/bitcoin_fa.ts132
-rw-r--r--src/qt/locale/bitcoin_fa_IR.ts458
-rw-r--r--src/qt/locale/bitcoin_fi.ts718
-rw-r--r--src/qt/locale/bitcoin_fr.ts74
-rw-r--r--src/qt/locale/bitcoin_fr_FR.ts398
-rw-r--r--src/qt/locale/bitcoin_gl.ts4
-rw-r--r--src/qt/locale/bitcoin_he.ts1250
-rw-r--r--src/qt/locale/bitcoin_hi_IN.ts12
-rw-r--r--src/qt/locale/bitcoin_hu.ts32
-rw-r--r--src/qt/locale/bitcoin_id_ID.ts434
-rw-r--r--src/qt/locale/bitcoin_it.ts1010
-rw-r--r--src/qt/locale/bitcoin_it_IT.ts20
-rw-r--r--src/qt/locale/bitcoin_ja.ts44
-rw-r--r--src/qt/locale/bitcoin_ka.ts174
-rw-r--r--src/qt/locale/bitcoin_ko_KR.ts1028
-rw-r--r--src/qt/locale/bitcoin_la.ts4
-rw-r--r--src/qt/locale/bitcoin_lv_LV.ts4
-rw-r--r--src/qt/locale/bitcoin_ms_MY.ts338
-rw-r--r--src/qt/locale/bitcoin_nb.ts548
-rw-r--r--src/qt/locale/bitcoin_ne.ts76
-rw-r--r--src/qt/locale/bitcoin_nl.ts312
-rw-r--r--src/qt/locale/bitcoin_pl.ts448
-rw-r--r--src/qt/locale/bitcoin_pt_BR.ts86
-rw-r--r--src/qt/locale/bitcoin_pt_PT.ts856
-rw-r--r--src/qt/locale/bitcoin_ro_RO.ts4
-rw-r--r--src/qt/locale/bitcoin_ru.ts34
-rw-r--r--src/qt/locale/bitcoin_ru_RU.ts622
-rw-r--r--src/qt/locale/bitcoin_sk.ts1356
-rw-r--r--src/qt/locale/bitcoin_sl_SI.ts100
-rw-r--r--src/qt/locale/bitcoin_sr.ts52
-rw-r--r--src/qt/locale/bitcoin_sv.ts1110
-rw-r--r--src/qt/locale/bitcoin_th_TH.ts16
-rw-r--r--src/qt/locale/bitcoin_tr.ts1612
-rw-r--r--src/qt/locale/bitcoin_uk.ts1052
-rw-r--r--src/qt/locale/bitcoin_ur_PK.ts24
-rw-r--r--src/qt/locale/bitcoin_uz@Cyrl.ts4
-rw-r--r--src/qt/locale/bitcoin_vi_VN.ts20
-rw-r--r--src/qt/locale/bitcoin_zh_CN.ts42
-rw-r--r--src/qt/locale/bitcoin_zh_HK.ts382
-rw-r--r--src/qt/locale/bitcoin_zh_TW.ts46
-rw-r--r--src/qt/macdockiconhandler.mm8
-rw-r--r--src/qt/macnotificationhandler.h7
-rw-r--r--src/qt/macnotificationhandler.mm16
-rw-r--r--src/qt/modaloverlay.cpp34
-rw-r--r--src/qt/modaloverlay.h5
-rw-r--r--src/qt/networkstyle.cpp2
-rw-r--r--src/qt/notificator.cpp68
-rw-r--r--src/qt/notificator.h3
-rw-r--r--src/qt/openuridialog.cpp2
-rw-r--r--src/qt/optionsdialog.cpp27
-rw-r--r--src/qt/optionsdialog.h1
-rw-r--r--src/qt/optionsmodel.cpp48
-rw-r--r--src/qt/optionsmodel.h14
-rw-r--r--src/qt/overviewpage.cpp2
-rw-r--r--src/qt/paymentrequestplus.cpp14
-rw-r--r--src/qt/paymentrequestplus.h3
-rw-r--r--src/qt/paymentserver.cpp43
-rw-r--r--src/qt/paymentserver.h14
-rw-r--r--src/qt/peertablemodel.cpp8
-rw-r--r--src/qt/platformstyle.cpp3
-rw-r--r--src/qt/receivecoinsdialog.cpp2
-rw-r--r--src/qt/receivecoinsdialog.h1
-rw-r--r--src/qt/receiverequestdialog.cpp2
-rw-r--r--src/qt/recentrequeststablemodel.cpp8
-rw-r--r--src/qt/rpcconsole.cpp65
-rw-r--r--src/qt/rpcconsole.h4
-rw-r--r--src/qt/sendcoinsdialog.cpp195
-rw-r--r--src/qt/sendcoinsdialog.h7
-rw-r--r--src/qt/signverifymessagedialog.cpp26
-rw-r--r--src/qt/splashscreen.cpp28
-rw-r--r--src/qt/splashscreen.h4
-rw-r--r--src/qt/test/paymentservertests.cpp24
-rw-r--r--src/qt/test/paymentservertests.h2
-rw-r--r--src/qt/test/rpcnestedtests.cpp37
-rw-r--r--src/qt/test/test_main.cpp58
-rw-r--r--src/qt/test/wallettests.cpp265
-rw-r--r--src/qt/test/wallettests.h15
-rw-r--r--src/qt/trafficgraphwidget.cpp11
-rw-r--r--src/qt/transactiondesc.cpp42
-rw-r--r--src/qt/transactionrecord.cpp34
-rw-r--r--src/qt/transactionrecord.h4
-rw-r--r--src/qt/transactiontablemodel.cpp8
-rw-r--r--src/qt/transactiontablemodel.h2
-rw-r--r--src/qt/transactionview.cpp63
-rw-r--r--src/qt/transactionview.h6
-rw-r--r--src/qt/utilitydialog.cpp6
-rw-r--r--src/qt/utilitydialog.h3
-rw-r--r--src/qt/walletframe.cpp2
-rw-r--r--src/qt/walletmodel.cpp188
-rw-r--r--src/qt/walletmodel.h11
-rw-r--r--src/qt/walletmodeltransaction.cpp10
-rw-r--r--src/qt/walletmodeltransaction.h8
-rw-r--r--src/qt/walletview.cpp2
-rw-r--r--src/qt/winshutdownmonitor.cpp2
-rw-r--r--src/random.cpp346
-rw-r--r--src/random.h111
-rw-r--r--src/rest.cpp139
-rw-r--r--src/reverse_iterator.h39
-rw-r--r--src/rpc/blockchain.cpp468
-rw-r--r--src/rpc/blockchain.h37
-rw-r--r--src/rpc/client.cpp33
-rw-r--r--src/rpc/mining.cpp435
-rw-r--r--src/rpc/mining.h18
-rw-r--r--src/rpc/misc.cpp461
-rw-r--r--src/rpc/net.cpp167
-rw-r--r--src/rpc/protocol.cpp56
-rw-r--r--src/rpc/protocol.h16
-rw-r--r--src/rpc/rawtransaction.cpp467
-rw-r--r--src/rpc/safemode.cpp14
-rw-r--r--src/rpc/safemode.h12
-rw-r--r--src/rpc/server.cpp187
-rw-r--r--src/rpc/server.h38
-rw-r--r--src/scheduler.cpp89
-rw-r--r--src/scheduler.h48
-rw-r--r--src/script/bitcoinconsensus.cpp8
-rw-r--r--src/script/bitcoinconsensus.h2
-rw-r--r--src/script/interpreter.cpp64
-rw-r--r--src/script/interpreter.h18
-rw-r--r--src/script/ismine.cpp16
-rw-r--r--src/script/script.cpp23
-rw-r--r--src/script/script.h45
-rw-r--r--src/script/script_error.cpp2
-rw-r--r--src/script/sigcache.cpp36
-rw-r--r--src/script/sigcache.h27
-rw-r--r--src/script/sign.cpp46
-rw-r--r--src/script/sign.h14
-rw-r--r--src/script/standard.cpp87
-rw-r--r--src/script/standard.h102
-rw-r--r--src/secp256k1/Makefile.am10
-rw-r--r--src/secp256k1/configure.ac17
-rw-r--r--src/secp256k1/contrib/lax_der_parsing.h10
-rw-r--r--src/secp256k1/contrib/lax_der_privatekey_parsing.h10
-rw-r--r--src/secp256k1/include/secp256k1.h62
-rw-r--r--src/secp256k1/include/secp256k1_ecdh.h16
-rw-r--r--src/secp256k1/include/secp256k1_recovery.h16
-rw-r--r--src/secp256k1/sage/group_prover.sage4
-rw-r--r--src/secp256k1/src/asm/field_10x26_arm.s4
-rw-r--r--src/secp256k1/src/basic-config.h9
-rw-r--r--src/secp256k1/src/bench.h8
-rw-r--r--src/secp256k1/src/bench_schnorr_verify.c73
-rw-r--r--src/secp256k1/src/ecdsa.h6
-rw-r--r--src/secp256k1/src/ecdsa_impl.h24
-rw-r--r--src/secp256k1/src/eckey.h6
-rw-r--r--src/secp256k1/src/eckey_impl.h17
-rw-r--r--src/secp256k1/src/ecmult.h6
-rw-r--r--src/secp256k1/src/ecmult_const.h6
-rw-r--r--src/secp256k1/src/ecmult_const_impl.h13
-rw-r--r--src/secp256k1/src/ecmult_gen.h6
-rw-r--r--src/secp256k1/src/ecmult_gen_impl.h6
-rw-r--r--src/secp256k1/src/ecmult_impl.h6
-rw-r--r--src/secp256k1/src/field.h6
-rw-r--r--src/secp256k1/src/field_10x26.h7
-rw-r--r--src/secp256k1/src/field_10x26_impl.h75
-rw-r--r--src/secp256k1/src/field_5x52.h6
-rw-r--r--src/secp256k1/src/field_5x52_asm_impl.h6
-rw-r--r--src/secp256k1/src/field_5x52_impl.h97
-rw-r--r--src/secp256k1/src/field_5x52_int128_impl.h6
-rw-r--r--src/secp256k1/src/field_impl.h6
-rw-r--r--src/secp256k1/src/group.h6
-rw-r--r--src/secp256k1/src/group_impl.h12
-rw-r--r--src/secp256k1/src/hash.h6
-rw-r--r--src/secp256k1/src/hash_impl.h6
-rw-r--r--src/secp256k1/src/modules/ecdh/main_impl.h8
-rw-r--r--src/secp256k1/src/modules/ecdh/tests_impl.h36
-rwxr-xr-xsrc/secp256k1/src/modules/recovery/main_impl.h8
-rw-r--r--src/secp256k1/src/modules/recovery/tests_impl.h149
-rw-r--r--src/secp256k1/src/num.h6
-rw-r--r--src/secp256k1/src/num_gmp.h6
-rw-r--r--src/secp256k1/src/num_gmp_impl.h6
-rw-r--r--src/secp256k1/src/num_impl.h6
-rw-r--r--src/secp256k1/src/scalar.h6
-rw-r--r--src/secp256k1/src/scalar_4x64.h6
-rw-r--r--src/secp256k1/src/scalar_4x64_impl.h6
-rw-r--r--src/secp256k1/src/scalar_8x32.h6
-rw-r--r--src/secp256k1/src/scalar_8x32_impl.h6
-rw-r--r--src/secp256k1/src/scalar_impl.h177
-rw-r--r--src/secp256k1/src/scalar_low.h6
-rw-r--r--src/secp256k1/src/scalar_low_impl.h6
-rw-r--r--[-rwxr-xr-x]src/secp256k1/src/secp256k1.c31
-rw-r--r--src/secp256k1/src/testrand.h6
-rw-r--r--src/secp256k1/src/testrand_impl.h6
-rw-r--r--src/secp256k1/src/tests.c51
-rw-r--r--src/secp256k1/src/tests_exhaustive.c143
-rw-r--r--src/secp256k1/src/util.h11
-rw-r--r--src/serialize.h29
-rw-r--r--src/streams.h64
-rw-r--r--src/support/allocators/secure.h10
-rw-r--r--src/support/allocators/zeroafterfree.h10
-rw-r--r--src/support/cleanse.cpp30
-rw-r--r--src/support/cleanse.h1
-rw-r--r--src/support/events.h12
-rw-r--r--src/support/lockedpool.cpp20
-rw-r--r--src/support/lockedpool.h16
-rw-r--r--src/sync.cpp69
-rw-r--r--src/sync.h10
-rw-r--r--src/test/DoS_tests.cpp47
-rw-r--r--src/test/README.md14
-rw-r--r--src/test/addrman_tests.cpp260
-rw-r--r--src/test/allocator_tests.cpp6
-rw-r--r--src/test/amount_tests.cpp39
-rw-r--r--src/test/arith_uint256_tests.cpp2
-rw-r--r--src/test/base58_tests.cpp158
-rw-r--r--src/test/bctest.py121
-rw-r--r--src/test/bech32_tests.cpp67
-rw-r--r--src/test/bip32_tests.cpp19
-rwxr-xr-xsrc/test/bitcoin-util-test.py46
-rw-r--r--src/test/blockencodings_tests.cpp34
-rw-r--r--src/test/bloom_tests.cpp19
-rw-r--r--src/test/buildenv.py.in2
-rw-r--r--src/test/checkqueue_tests.cpp442
-rw-r--r--src/test/coins_tests.cpp628
-rw-r--r--src/test/crypto_tests.cpp116
-rw-r--r--src/test/cuckoocache_tests.cpp68
-rw-r--r--src/test/data/base58_keys_invalid.json30
-rw-r--r--src/test/data/base58_keys_valid.json679
-rw-r--r--src/test/data/bitcoin-util-test.json356
-rw-r--r--src/test/data/blanktxv1.hex1
-rw-r--r--src/test/data/blanktxv1.json11
-rw-r--r--src/test/data/blanktxv2.hex1
-rw-r--r--src/test/data/blanktxv2.json11
-rw-r--r--src/test/data/script_tests.json10
-rw-r--r--src/test/data/tt-delin1-out.hex1
-rw-r--r--src/test/data/tt-delin1-out.json217
-rw-r--r--src/test/data/tt-delout1-out.hex1
-rw-r--r--src/test/data/tt-delout1-out.json213
-rw-r--r--src/test/data/tt-locktime317000-out.hex1
-rw-r--r--src/test/data/tt-locktime317000-out.json226
-rw-r--r--src/test/data/tx394b54bb.hex1
-rw-r--r--src/test/data/tx_invalid.json4
-rw-r--r--src/test/data/tx_valid.json6
-rw-r--r--src/test/data/txcreate1.hex1
-rw-r--r--src/test/data/txcreate1.json64
-rw-r--r--src/test/data/txcreate2.hex1
-rw-r--r--src/test/data/txcreate2.json20
-rw-r--r--src/test/data/txcreatedata1.hex1
-rw-r--r--src/test/data/txcreatedata1.json42
-rw-r--r--src/test/data/txcreatedata2.hex1
-rw-r--r--src/test/data/txcreatedata2.json42
-rw-r--r--src/test/data/txcreatedata_seq0.hex1
-rw-r--r--src/test/data/txcreatedata_seq0.json33
-rw-r--r--src/test/data/txcreatedata_seq1.hex1
-rw-r--r--src/test/data/txcreatedata_seq1.json42
-rw-r--r--src/test/data/txcreatemultisig1.hex1
-rw-r--r--src/test/data/txcreatemultisig1.json26
-rw-r--r--src/test/data/txcreatemultisig2.hex1
-rw-r--r--src/test/data/txcreatemultisig2.json24
-rw-r--r--src/test/data/txcreatemultisig3.hex1
-rw-r--r--src/test/data/txcreatemultisig3.json20
-rw-r--r--src/test/data/txcreatemultisig4.hex1
-rw-r--r--src/test/data/txcreatemultisig4.json24
-rw-r--r--src/test/data/txcreateoutpubkey1.hex1
-rw-r--r--src/test/data/txcreateoutpubkey1.json24
-rw-r--r--src/test/data/txcreateoutpubkey2.hex1
-rw-r--r--src/test/data/txcreateoutpubkey2.json20
-rw-r--r--src/test/data/txcreateoutpubkey3.hex1
-rw-r--r--src/test/data/txcreateoutpubkey3.json24
-rw-r--r--src/test/data/txcreatescript1.hex1
-rw-r--r--src/test/data/txcreatescript1.json20
-rw-r--r--src/test/data/txcreatescript2.hex1
-rw-r--r--src/test/data/txcreatescript2.json24
-rw-r--r--src/test/data/txcreatescript3.hex1
-rw-r--r--src/test/data/txcreatescript3.json20
-rw-r--r--src/test/data/txcreatescript4.hex1
-rw-r--r--src/test/data/txcreatescript4.json24
-rw-r--r--src/test/data/txcreatesignv1.hex1
-rw-r--r--src/test/data/txcreatesignv1.json33
-rw-r--r--src/test/data/txcreatesignv2.hex1
-rw-r--r--src/test/dbwrapper_tests.cpp97
-rw-r--r--src/test/getarg_tests.cpp115
-rw-r--r--src/test/hash_tests.cpp17
-rw-r--r--src/test/key_tests.cpp55
-rw-r--r--src/test/limitedmap_tests.cpp2
-rw-r--r--src/test/main_tests.cpp7
-rw-r--r--src/test/mempool_tests.cpp57
-rw-r--r--src/test/merkle_tests.cpp7
-rw-r--r--src/test/merkleblock_tests.cpp78
-rw-r--r--src/test/miner_tests.cpp77
-rw-r--r--src/test/multisig_tests.cpp110
-rw-r--r--src/test/net_tests.cpp21
-rw-r--r--src/test/netbase_tests.cpp44
-rw-r--r--src/test/pmt_tests.cpp27
-rw-r--r--src/test/policyestimator_tests.cpp84
-rw-r--r--src/test/pow_tests.cpp40
-rw-r--r--src/test/prevector_tests.cpp88
-rw-r--r--src/test/raii_event_tests.cpp18
-rw-r--r--src/test/random_tests.cpp60
-rw-r--r--src/test/rpc_tests.cpp12
-rw-r--r--src/test/scheduler_tests.cpp14
-rw-r--r--src/test/script_P2SH_tests.cpp7
-rw-r--r--src/test/script_standard_tests.cpp741
-rw-r--r--src/test/script_tests.cpp85
-rw-r--r--src/test/scriptnum_tests.cpp14
-rw-r--r--src/test/serialize_tests.cpp4
-rw-r--r--src/test/sighash_tests.cpp37
-rw-r--r--src/test/sigopcount_tests.cpp6
-rw-r--r--src/test/skiplist_tests.cpp64
-rw-r--r--src/test/streams_tests.cpp1
-rw-r--r--src/test/test_bitcoin.cpp87
-rw-r--r--src/test/test_bitcoin.h46
-rw-r--r--src/test/test_bitcoin_fuzzy.cpp69
-rw-r--r--src/test/test_bitcoin_main.cpp26
-rw-r--r--src/test/test_random.h23
-rw-r--r--src/test/testutil.cpp33
-rw-r--r--src/test/testutil.h15
-rw-r--r--src/test/torcontrol_tests.cpp199
-rw-r--r--src/test/transaction_tests.cpp81
-rw-r--r--src/test/txvalidationcache_tests.cpp287
-rw-r--r--src/test/util_tests.cpp151
-rw-r--r--src/test/versionbits_tests.cpp57
-rw-r--r--src/timedata.cpp26
-rw-r--r--src/timedata.h14
-rw-r--r--src/tinyformat.h15
-rw-r--r--src/torcontrol.cpp206
-rw-r--r--src/txdb.cpp275
-rw-r--r--src/txdb.h61
-rw-r--r--src/txmempool.cpp291
-rw-r--r--src/txmempool.h267
-rw-r--r--src/ui_interface.h9
-rw-r--r--src/uint256.cpp7
-rw-r--r--src/uint256.h2
-rw-r--r--src/undo.h85
-rw-r--r--src/univalue/lib/univalue_utffilter.h2
-rw-r--r--src/util.cpp355
-rw-r--r--src/util.h243
-rw-r--r--src/utilmoneystr.cpp8
-rw-r--r--src/utilmoneystr.h3
-rw-r--r--src/utilstrencodings.cpp105
-rw-r--r--src/utilstrencodings.h41
-rw-r--r--src/utiltime.cpp27
-rw-r--r--src/utiltime.h13
-rw-r--r--src/validation.cpp2065
-rw-r--r--src/validation.h216
-rw-r--r--src/validationinterface.cpp136
-rw-r--r--src/validationinterface.h83
-rw-r--r--src/version.h3
-rw-r--r--src/versionbits.cpp62
-rw-r--r--src/versionbits.h16
-rw-r--r--src/wallet/coincontrol.h28
-rw-r--r--src/wallet/crypter.cpp15
-rw-r--r--src/wallet/crypter.h40
-rw-r--r--src/wallet/db.cpp399
-rw-r--r--src/wallet/db.h157
-rw-r--r--src/wallet/feebumper.cpp291
-rw-r--r--src/wallet/feebumper.h61
-rw-r--r--src/wallet/fees.cpp89
-rw-r--r--src/wallet/fees.h34
-rw-r--r--src/wallet/init.cpp279
-rw-r--r--src/wallet/init.h43
-rw-r--r--src/wallet/rpcdump.cpp563
-rw-r--r--src/wallet/rpcwallet.cpp1890
-rw-r--r--src/wallet/rpcwallet.h16
-rw-r--r--src/wallet/test/accounting_tests.cpp3
-rw-r--r--src/wallet/test/crypto_tests.cpp140
-rw-r--r--src/wallet/test/wallet_test_fixture.cpp7
-rw-r--r--src/wallet/test/wallet_test_fixture.h2
-rw-r--r--src/wallet/test/wallet_tests.cpp427
-rw-r--r--src/wallet/wallet.cpp2370
-rw-r--r--src/wallet/wallet.h436
-rw-r--r--src/wallet/walletdb.cpp484
-rw-r--r--src/wallet/walletdb.h103
-rw-r--r--src/warnings.cpp8
-rw-r--r--src/warnings.h8
-rw-r--r--src/zmq/zmqabstractnotifier.h2
-rw-r--r--src/zmq/zmqnotificationinterface.cpp46
-rw-r--r--src/zmq/zmqnotificationinterface.h9
-rw-r--r--src/zmq/zmqpublishnotifier.cpp20
-rw-r--r--src/zmq/zmqpublishnotifier.h12
575 files changed, 43069 insertions, 18745 deletions
diff --git a/src/.clang-format b/src/.clang-format
index 129f062ef8..2d2ee67035 100644
--- a/src/.clang-format
+++ b/src/.clang-format
@@ -6,7 +6,7 @@ AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
-AllowShortIfStatementsOnASingleLine: false
+AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: false
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
@@ -23,7 +23,6 @@ ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
-ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH, BOOST_REVERSE_FOREACH ]
IndentCaseLabels: false
IndentFunctionDeclarationAfterType: false
IndentWidth: 4
@@ -47,6 +46,6 @@ SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
-Standard: Cpp03
+Standard: Cpp11
TabWidth: 8
UseTab: Never
diff --git a/src/Makefile.am b/src/Makefile.am
index a2072865a3..90deff48b0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -5,7 +5,7 @@
DIST_SUBDIRS = secp256k1 univalue
AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS)
-AM_CXXFLAGS = $(HARDENED_CXXFLAGS)
+AM_CXXFLAGS = $(HARDENED_CXXFLAGS) $(ERROR_CXXFLAGS)
AM_CPPFLAGS = $(HARDENED_CPPFLAGS)
EXTRA_LIBRARIES =
@@ -18,7 +18,6 @@ else
LIBUNIVALUE = $(UNIVALUE_LIBS)
endif
-BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config
BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS)
BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include
@@ -79,6 +78,7 @@ BITCOIN_CORE_H = \
addrdb.h \
addrman.h \
base58.h \
+ bech32.h \
bloom.h \
blockencodings.h \
chain.h \
@@ -95,9 +95,11 @@ BITCOIN_CORE_H = \
compat/sanity.h \
compressor.h \
consensus/consensus.h \
+ consensus/tx_verify.h \
core_io.h \
core_memusage.h \
cuckoocache.h \
+ fs.h \
httprpc.h \
httpserver.h \
indirectmap.h \
@@ -115,15 +117,20 @@ BITCOIN_CORE_H = \
netbase.h \
netmessagemaker.h \
noui.h \
+ policy/feerate.h \
policy/fees.h \
policy/policy.h \
policy/rbf.h \
pow.h \
protocol.h \
random.h \
+ reverse_iterator.h \
reverselock.h \
+ rpc/blockchain.h \
rpc/client.h \
+ rpc/mining.h \
rpc/protocol.h \
+ rpc/safemode.h \
rpc/server.h \
rpc/register.h \
scheduler.h \
@@ -155,6 +162,9 @@ BITCOIN_CORE_H = \
wallet/coincontrol.h \
wallet/crypter.h \
wallet/db.h \
+ wallet/feebumper.h \
+ wallet/fees.h \
+ wallet/init.h \
wallet/rpcwallet.h \
wallet/wallet.h \
wallet/walletdb.h \
@@ -167,20 +177,21 @@ BITCOIN_CORE_H = \
obj/build.h: FORCE
@$(MKDIR_P) $(builddir)/obj
- @$(top_srcdir)/share/genbuild.sh $(abs_top_builddir)/src/obj/build.h \
- $(abs_top_srcdir)
+ @$(top_srcdir)/share/genbuild.sh "$(abs_top_builddir)/src/obj/build.h" \
+ "$(abs_top_srcdir)"
libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h
# server: shared between bitcoind and bitcoin-qt
libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_server_a_SOURCES = \
- addrman.cpp \
addrdb.cpp \
+ addrman.cpp \
bloom.cpp \
blockencodings.cpp \
chain.cpp \
checkpoints.cpp \
+ consensus/tx_verify.cpp \
httprpc.cpp \
httpserver.cpp \
init.cpp \
@@ -192,6 +203,7 @@ libbitcoin_server_a_SOURCES = \
noui.cpp \
policy/fees.cpp \
policy/policy.cpp \
+ policy/rbf.cpp \
pow.cpp \
rest.cpp \
rpc/blockchain.cpp \
@@ -199,6 +211,7 @@ libbitcoin_server_a_SOURCES = \
rpc/misc.cpp \
rpc/net.cpp \
rpc/rawtransaction.cpp \
+ rpc/safemode.cpp \
rpc/server.cpp \
script/sigcache.cpp \
script/ismine.cpp \
@@ -229,19 +242,23 @@ libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_wallet_a_SOURCES = \
wallet/crypter.cpp \
wallet/db.cpp \
+ wallet/feebumper.cpp \
+ wallet/fees.cpp \
+ wallet/init.cpp \
wallet/rpcdump.cpp \
wallet/rpcwallet.cpp \
wallet/wallet.cpp \
wallet/walletdb.cpp \
- policy/rbf.cpp \
$(BITCOIN_CORE_H)
# crypto primitives library
-crypto_libbitcoin_crypto_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_CONFIG_INCLUDES)
+crypto_libbitcoin_crypto_a_CPPFLAGS = $(AM_CPPFLAGS)
crypto_libbitcoin_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
crypto_libbitcoin_crypto_a_SOURCES = \
crypto/aes.cpp \
crypto/aes.h \
+ crypto/chacha20.h \
+ crypto/chacha20.cpp \
crypto/common.h \
crypto/hmac_sha256.cpp \
crypto/hmac_sha256.h \
@@ -256,6 +273,10 @@ crypto_libbitcoin_crypto_a_SOURCES = \
crypto/sha512.cpp \
crypto/sha512.h
+if USE_ASM
+crypto_libbitcoin_crypto_a_SOURCES += crypto/sha256_sse4.cpp
+endif
+
# consensus: shared between all executables that validate any consensus rules.
libbitcoin_consensus_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
libbitcoin_consensus_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
@@ -295,8 +316,8 @@ libbitcoin_consensus_a_SOURCES = \
libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
libbitcoin_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_common_a_SOURCES = \
- amount.cpp \
base58.cpp \
+ bech32.cpp \
chainparams.cpp \
coins.cpp \
compressor.cpp \
@@ -306,6 +327,7 @@ libbitcoin_common_a_SOURCES = \
keystore.cpp \
netaddress.cpp \
netbase.cpp \
+ policy/feerate.cpp \
protocol.cpp \
scheduler.cpp \
script/sign.cpp \
@@ -325,6 +347,7 @@ libbitcoin_util_a_SOURCES = \
compat/glibc_sanity.cpp \
compat/glibcxx_sanity.cpp \
compat/strnlen.cpp \
+ fs.cpp \
random.cpp \
rpc/protocol.cpp \
support/cleanse.cpp \
@@ -370,6 +393,7 @@ bitcoind_LDADD = \
$(LIBBITCOIN_CONSENSUS) \
$(LIBBITCOIN_CRYPTO) \
$(LIBLEVELDB) \
+ $(LIBLEVELDB_SSE42) \
$(LIBMEMENV) \
$(LIBSECP256K1)
@@ -452,11 +476,18 @@ CLEANFILES += univalue/*.gcda univalue/*.gcno
CLEANFILES += wallet/*.gcda wallet/*.gcno
CLEANFILES += wallet/test/*.gcda wallet/test/*.gcno
CLEANFILES += zmq/*.gcda zmq/*.gcno
-
-DISTCLEANFILES = obj/build.h
+CLEANFILES += obj/build.h
EXTRA_DIST = $(CTAES_DIST)
+
+config/bitcoin-config.h: config/stamp-h1
+ @$(MAKE) -C $(top_builddir) $(subdir)/$(@)
+config/stamp-h1: $(top_srcdir)/$(subdir)/config/bitcoin-config.h.in $(top_builddir)/config.status
+ $(AM_V_at)$(MAKE) -C $(top_builddir) $(subdir)/$(@)
+$(top_srcdir)/$(subdir)/config/bitcoin-config.h.in: $(am__configure_deps)
+ $(AM_V_at)$(MAKE) -C $(top_srcdir) $(subdir)/config/bitcoin-config.h.in
+
clean-local:
-$(MAKE) -C secp256k1 clean
-$(MAKE) -C univalue clean
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index e58bd9dfbf..8e2e587d32 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -6,15 +6,17 @@ bin_PROGRAMS += bench/bench_bitcoin
BENCH_SRCDIR = bench
BENCH_BINARY = bench/bench_bitcoin$(EXEEXT)
-RAW_TEST_FILES = \
+RAW_BENCH_FILES = \
bench/data/block413567.raw
-GENERATED_TEST_FILES = $(RAW_TEST_FILES:.raw=.raw.h)
+GENERATED_BENCH_FILES = $(RAW_BENCH_FILES:.raw=.raw.h)
bench_bench_bitcoin_SOURCES = \
+ $(RAW_BENCH_FILES) \
bench/bench_bitcoin.cpp \
bench/bench.cpp \
bench/bench.h \
bench/checkblock.cpp \
+ bench/checkqueue.cpp \
bench/Examples.cpp \
bench/rollingbloom.cpp \
bench/crypto_hash.cpp \
@@ -24,9 +26,10 @@ bench_bench_bitcoin_SOURCES = \
bench/base58.cpp \
bench/lockedpool.cpp \
bench/perf.cpp \
- bench/perf.h
+ bench/perf.h \
+ bench/prevector_destructor.cpp
-nodist_bench_bench_bitcoin_SOURCES = $(GENERATED_TEST_FILES)
+nodist_bench_bench_bitcoin_SOURCES = $(GENERATED_BENCH_FILES)
bench_bench_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CLFAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/
bench_bench_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
@@ -37,6 +40,7 @@ bench_bench_bitcoin_LDADD = \
$(LIBBITCOIN_CONSENSUS) \
$(LIBBITCOIN_CRYPTO) \
$(LIBLEVELDB) \
+ $(LIBLEVELDB_SSE42) \
$(LIBMEMENV) \
$(LIBSECP256K1) \
$(LIBUNIVALUE)
@@ -53,7 +57,7 @@ endif
bench_bench_bitcoin_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
bench_bench_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
-CLEAN_BITCOIN_BENCH = bench/*.gcda bench/*.gcno $(GENERATED_TEST_FILES)
+CLEAN_BITCOIN_BENCH = bench/*.gcda bench/*.gcno $(GENERATED_BENCH_FILES)
CLEANFILES += $(CLEAN_BITCOIN_BENCH)
diff --git a/src/Makefile.leveldb.include b/src/Makefile.leveldb.include
index 358f39cbef..833f3d2a10 100644
--- a/src/Makefile.leveldb.include
+++ b/src/Makefile.leveldb.include
@@ -4,12 +4,15 @@
LIBLEVELDB_INT = leveldb/libleveldb.a
LIBMEMENV_INT = leveldb/libmemenv.a
+LIBLEVELDB_SSE42_INT = leveldb/libleveldb_sse42.a
EXTRA_LIBRARIES += $(LIBLEVELDB_INT)
EXTRA_LIBRARIES += $(LIBMEMENV_INT)
+EXTRA_LIBRARIES += $(LIBLEVELDB_SSE42_INT)
LIBLEVELDB += $(LIBLEVELDB_INT)
LIBMEMENV += $(LIBMEMENV_INT)
+LIBLEVELDB_SSE42 = $(LIBLEVELDB_SSE42_INT)
LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include
LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/helpers/memenv
@@ -74,6 +77,7 @@ leveldb_libleveldb_a_SOURCES += leveldb/table/merger.h
leveldb_libleveldb_a_SOURCES += leveldb/table/format.h
leveldb_libleveldb_a_SOURCES += leveldb/table/iterator_wrapper.h
leveldb_libleveldb_a_SOURCES += leveldb/util/crc32c.h
+leveldb_libleveldb_a_SOURCES += leveldb/util/env_posix_test_helper.h
leveldb_libleveldb_a_SOURCES += leveldb/util/arena.h
leveldb_libleveldb_a_SOURCES += leveldb/util/random.h
leveldb_libleveldb_a_SOURCES += leveldb/util/posix_logger.h
@@ -135,3 +139,11 @@ leveldb_libmemenv_a_CPPFLAGS = $(leveldb_libleveldb_a_CPPFLAGS)
leveldb_libmemenv_a_CXXFLAGS = $(leveldb_libleveldb_a_CXXFLAGS)
leveldb_libmemenv_a_SOURCES = leveldb/helpers/memenv/memenv.cc
leveldb_libmemenv_a_SOURCES += leveldb/helpers/memenv/memenv.h
+
+leveldb_libleveldb_sse42_a_CPPFLAGS = $(leveldb_libleveldb_a_CPPFLAGS)
+leveldb_libleveldb_sse42_a_CXXFLAGS = $(leveldb_libleveldb_a_CXXFLAGS)
+if ENABLE_HWCRC32
+leveldb_libleveldb_sse42_a_CPPFLAGS += -DLEVELDB_PLATFORM_POSIX_SSE
+leveldb_libleveldb_sse42_a_CXXFLAGS += $(SSE42_CXXFLAGS)
+endif
+leveldb_libleveldb_sse42_a_SOURCES = leveldb/port/port_posix_sse.cc
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index edc3c4b292..e4b64c1ca7 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -122,6 +122,7 @@ QT_MOC_CPP = \
qt/moc_bitcoinamountfield.cpp \
qt/moc_bitcoingui.cpp \
qt/moc_bitcoinunits.cpp \
+ qt/moc_callback.cpp \
qt/moc_clientmodel.cpp \
qt/moc_coincontroldialog.cpp \
qt/moc_coincontroltreewidget.cpp \
@@ -167,6 +168,7 @@ BITCOIN_MM = \
QT_MOC = \
qt/bitcoin.moc \
qt/bitcoinamountfield.moc \
+ qt/callback.moc \
qt/intro.moc \
qt/overviewpage.moc \
qt/rpcconsole.moc
@@ -189,6 +191,7 @@ BITCOIN_QT_H = \
qt/bitcoinamountfield.h \
qt/bitcoingui.h \
qt/bitcoinunits.h \
+ qt/callback.h \
qt/clientmodel.h \
qt/coincontroldialog.h \
qt/coincontroltreewidget.h \
@@ -404,7 +407,7 @@ endif
if ENABLE_ZMQ
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
-qt_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
+qt_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \
$(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)
diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include
index 039f8ac547..ea2ed17472 100644
--- a/src/Makefile.qttest.include
+++ b/src/Makefile.qttest.include
@@ -11,7 +11,9 @@ TEST_QT_MOC_CPP = \
qt/test/moc_uritests.cpp
if ENABLE_WALLET
-TEST_QT_MOC_CPP += qt/test/moc_paymentservertests.cpp
+TEST_QT_MOC_CPP += \
+ qt/test/moc_paymentservertests.cpp \
+ qt/test/moc_wallettests.cpp
endif
TEST_QT_H = \
@@ -19,7 +21,14 @@ TEST_QT_H = \
qt/test/rpcnestedtests.h \
qt/test/uritests.h \
qt/test/paymentrequestdata.h \
- qt/test/paymentservertests.h
+ qt/test/paymentservertests.h \
+ qt/test/wallettests.h
+
+TEST_BITCOIN_CPP = \
+ test/test_bitcoin.cpp
+
+TEST_BITCOIN_H = \
+ test/test_bitcoin.h
qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \
$(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS)
@@ -29,10 +38,14 @@ qt_test_test_bitcoin_qt_SOURCES = \
qt/test/rpcnestedtests.cpp \
qt/test/test_main.cpp \
qt/test/uritests.cpp \
- $(TEST_QT_H)
+ $(TEST_QT_H) \
+ $(TEST_BITCOIN_CPP) \
+ $(TEST_BITCOIN_H)
if ENABLE_WALLET
qt_test_test_bitcoin_qt_SOURCES += \
- qt/test/paymentservertests.cpp
+ qt/test/paymentservertests.cpp \
+ qt/test/wallettests.cpp \
+ wallet/test/wallet_test_fixture.cpp
endif
nodist_qt_test_test_bitcoin_qt_SOURCES = $(TEST_QT_MOC_CPP)
@@ -45,7 +58,7 @@ 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_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) \
- $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
+ $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
$(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)
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 4d44b35bb6..d3e7b5da12 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -8,60 +8,6 @@ noinst_PROGRAMS += test/test_bitcoin_fuzzy
TEST_SRCDIR = test
TEST_BINARY=test/test_bitcoin$(EXEEXT)
-
-EXTRA_DIST += \
- test/bctest.py \
- test/bitcoin-util-test.py \
- test/data/bitcoin-util-test.json \
- test/data/blanktxv1.hex \
- test/data/blanktxv1.json \
- test/data/blanktxv2.hex \
- test/data/blanktxv2.json \
- test/data/tt-delin1-out.hex \
- test/data/tt-delin1-out.json \
- test/data/tt-delout1-out.hex \
- test/data/tt-delout1-out.json \
- test/data/tt-locktime317000-out.hex \
- test/data/tt-locktime317000-out.json \
- test/data/tx394b54bb.hex \
- test/data/txcreate1.hex \
- test/data/txcreate1.json \
- test/data/txcreate2.hex \
- test/data/txcreate2.json \
- test/data/txcreatedata1.hex \
- test/data/txcreatedata1.json \
- test/data/txcreatedata2.hex \
- test/data/txcreatedata2.json \
- test/data/txcreatedata_seq0.hex \
- test/data/txcreatedata_seq0.json \
- test/data/txcreatedata_seq1.hex \
- test/data/txcreatedata_seq1.json \
- test/data/txcreatemultisig1.hex \
- test/data/txcreatemultisig1.json \
- test/data/txcreatemultisig2.hex \
- test/data/txcreatemultisig2.json \
- test/data/txcreatemultisig3.hex \
- test/data/txcreatemultisig3.json \
- test/data/txcreatemultisig4.hex \
- test/data/txcreatemultisig4.json \
- test/data/txcreateoutpubkey1.hex \
- test/data/txcreateoutpubkey1.json \
- test/data/txcreateoutpubkey2.hex \
- test/data/txcreateoutpubkey2.json \
- test/data/txcreateoutpubkey3.hex \
- test/data/txcreateoutpubkey3.json \
- test/data/txcreatescript1.hex \
- test/data/txcreatescript1.json \
- test/data/txcreatescript2.hex \
- test/data/txcreatescript2.json \
- test/data/txcreatescript3.hex \
- test/data/txcreatescript3.json \
- test/data/txcreatescript4.hex \
- test/data/txcreatescript4.json \
- test/data/txcreatesignv1.hex \
- test/data/txcreatesignv1.json \
- test/data/txcreatesignv2.hex
-
JSON_TEST_FILES = \
test/data/script_tests.json \
test/data/base58_keys_valid.json \
@@ -85,10 +31,12 @@ BITCOIN_TESTS =\
test/base32_tests.cpp \
test/base58_tests.cpp \
test/base64_tests.cpp \
+ test/bech32_tests.cpp \
test/bip32_tests.cpp \
test/blockencodings_tests.cpp \
test/bloom_tests.cpp \
test/bswap_tests.cpp \
+ test/checkqueue_tests.cpp \
test/coins_tests.cpp \
test/compress_tests.cpp \
test/crypto_tests.cpp \
@@ -102,6 +50,7 @@ BITCOIN_TESTS =\
test/main_tests.cpp \
test/mempool_tests.cpp \
test/merkle_tests.cpp \
+ test/merkleblock_tests.cpp \
test/miner_tests.cpp \
test/multisig_tests.cpp \
test/net_tests.cpp \
@@ -111,12 +60,14 @@ BITCOIN_TESTS =\
test/pow_tests.cpp \
test/prevector_tests.cpp \
test/raii_event_tests.cpp \
+ test/random_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/script_standard_tests.cpp \
test/scriptnum_tests.cpp \
test/serialize_tests.cpp \
test/sighash_tests.cpp \
@@ -125,10 +76,9 @@ BITCOIN_TESTS =\
test/streams_tests.cpp \
test/test_bitcoin.cpp \
test/test_bitcoin.h \
- test/test_random.h \
- test/testutil.cpp \
- test/testutil.h \
+ test/test_bitcoin_main.cpp \
test/timedata_tests.cpp \
+ test/torcontrol_tests.cpp \
test/transaction_tests.cpp \
test/txvalidationcache_tests.cpp \
test/versionbits_tests.cpp \
@@ -147,12 +97,13 @@ endif
test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS)
-test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
- $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS)
-test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_test_bitcoin_LDADD =
if ENABLE_WALLET
test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
endif
+test_test_bitcoin_LDADD += $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) \
+ $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS)
+test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
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
@@ -188,9 +139,6 @@ CLEAN_BITCOIN_TEST = test/*.gcda test/*.gcno $(GENERATED_TEST_FILES)
CLEANFILES += $(CLEAN_BITCOIN_TEST)
-# This file is problematic for out-of-tree builds if it exists.
-DISTCLEANFILES += test/buildenv.pyc
-
bitcoin_test: $(TEST_BINARY)
bitcoin_test_check: $(TEST_BINARY) FORCE
@@ -200,8 +148,8 @@ bitcoin_test_clean : FORCE
rm -f $(CLEAN_BITCOIN_TEST) $(test_test_bitcoin_OBJECTS) $(TEST_BINARY)
check-local:
- @echo "Running test/bitcoin-util-test.py..."
- $(AM_V_at)srcdir=$(srcdir) PYTHONPATH=$(builddir)/test $(PYTHON) $(srcdir)/test/bitcoin-util-test.py
+ @echo "Running test/util/bitcoin-util-test.py..."
+ $(PYTHON) $(top_builddir)/test/util/bitcoin-util-test.py
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check
if EMBEDDED_UNIVALUE
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue check
diff --git a/src/addrdb.cpp b/src/addrdb.cpp
index 224d3921cc..7f85c16585 100644
--- a/src/addrdb.cpp
+++ b/src/addrdb.cpp
@@ -8,103 +8,81 @@
#include "addrman.h"
#include "chainparams.h"
#include "clientversion.h"
+#include "fs.h"
#include "hash.h"
#include "random.h"
#include "streams.h"
#include "tinyformat.h"
#include "util.h"
-#include <boost/filesystem.hpp>
+namespace {
-CBanDB::CBanDB()
+template <typename Stream, typename Data>
+bool SerializeDB(Stream& stream, const Data& data)
{
- pathBanlist = GetDataDir() / "banlist.dat";
+ // Write and commit header, data
+ try {
+ CHashWriter hasher(SER_DISK, CLIENT_VERSION);
+ stream << FLATDATA(Params().MessageStart()) << data;
+ hasher << FLATDATA(Params().MessageStart()) << data;
+ stream << hasher.GetHash();
+ } catch (const std::exception& e) {
+ return error("%s: Serialize or I/O error - %s", __func__, e.what());
+ }
+
+ return true;
}
-bool CBanDB::Write(const banmap_t& banSet)
+template <typename Data>
+bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data& data)
{
// 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;
+ std::string tmpfn = strprintf("%s.%04x", prefix, randv);
// open temp output file, and associate with CAutoFile
- boost::filesystem::path pathTmp = GetDataDir() / tmpfn;
- FILE *file = fopen(pathTmp.string().c_str(), "wb");
+ fs::path pathTmp = GetDataDir() / tmpfn;
+ FILE *file = fsbridge::fopen(pathTmp, "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());
- }
+ // Serialize
+ if (!SerializeDB(fileout, data)) return false;
FileCommit(fileout.Get());
fileout.fclose();
- // replace existing banlist.dat, if any, with new banlist.dat.XXXX
- if (!RenameOver(pathTmp, pathBanlist))
+ // replace existing file, if any, with new file
+ if (!RenameOver(pathTmp, path))
return error("%s: Rename-into-place failed", __func__);
return true;
}
-bool CBanDB::Read(banmap_t& banSet)
+template <typename Stream, typename Data>
+bool DeserializeDB(Stream& stream, Data& data, bool fCheckSum = true)
{
- // 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);
- std::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 {
+ CHashVerifier<Stream> verifier(&stream);
// de-serialize file header (network specific magic number) and ..
- ssBanlist >> FLATDATA(pchMsgTmp);
-
+ unsigned char pchMsgTmp[4];
+ verifier >> FLATDATA(pchMsgTmp);
// ... verify the network matches ours
if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
return error("%s: Invalid network magic number", __func__);
- // de-serialize ban data
- ssBanlist >> banSet;
+ // de-serialize data
+ verifier >> data;
+
+ // verify checksum
+ if (fCheckSum) {
+ uint256 hashTmp;
+ stream >> hashTmp;
+ if (hashTmp != verifier.GetHash()) {
+ return error("%s: Checksum mismatch, data corrupted", __func__);
+ }
+ }
}
catch (const std::exception& e) {
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
@@ -113,106 +91,56 @@ bool CBanDB::Read(banmap_t& banSet)
return true;
}
-CAddrDB::CAddrDB()
+template <typename Data>
+bool DeserializeFileDB(const fs::path& path, Data& data)
{
- pathAddr = GetDataDir() / "peers.dat";
+ // open input file, and associate with CAutoFile
+ FILE *file = fsbridge::fopen(path, "rb");
+ CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
+ if (filein.IsNull())
+ return error("%s: Failed to open file %s", __func__, path.string());
+
+ return DeserializeDB(filein, data);
}
-bool CAddrDB::Write(const CAddrMan& addr)
-{
- // Generate random temporary filename
- unsigned short randv = 0;
- GetRandBytes((unsigned char*)&randv, sizeof(randv));
- std::string tmpfn = strprintf("peers.dat.%04x", randv);
+}
- // serialize addresses, checksum data up to that point, then append csum
- CDataStream ssPeers(SER_DISK, CLIENT_VERSION);
- ssPeers << FLATDATA(Params().MessageStart());
- ssPeers << addr;
- uint256 hash = Hash(ssPeers.begin(), ssPeers.end());
- ssPeers << hash;
+CBanDB::CBanDB()
+{
+ pathBanlist = GetDataDir() / "banlist.dat";
+}
- // 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());
+bool CBanDB::Write(const banmap_t& banSet)
+{
+ return SerializeFileDB("banlist", pathBanlist, banSet);
+}
- // Write and commit header, data
- try {
- fileout << ssPeers;
- }
- catch (const std::exception& e) {
- return error("%s: Serialize or I/O error - %s", __func__, e.what());
- }
- FileCommit(fileout.Get());
- fileout.fclose();
+bool CBanDB::Read(banmap_t& banSet)
+{
+ return DeserializeFileDB(pathBanlist, banSet);
+}
- // replace existing peers.dat, if any, with new peers.dat.XXXX
- if (!RenameOver(pathTmp, pathAddr))
- return error("%s: Rename-into-place failed", __func__);
+CAddrDB::CAddrDB()
+{
+ pathAddr = GetDataDir() / "peers.dat";
+}
- return true;
+bool CAddrDB::Write(const CAddrMan& addr)
+{
+ return SerializeFileDB("peers", pathAddr, addr);
}
bool CAddrDB::Read(CAddrMan& addr)
{
- // open input file, and associate with CAutoFile
- FILE *file = fopen(pathAddr.string().c_str(), "rb");
- CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
- if (filein.IsNull())
- return error("%s: Failed to open file %s", __func__, pathAddr.string());
-
- // use file size to size memory buffer
- 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 (fileSize >= sizeof(uint256))
- dataSize = fileSize - sizeof(uint256);
- std::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 ssPeers(vchData, SER_DISK, CLIENT_VERSION);
-
- // verify stored checksum matches input data
- uint256 hashTmp = Hash(ssPeers.begin(), ssPeers.end());
- if (hashIn != hashTmp)
- return error("%s: Checksum mismatch, data corrupted", __func__);
-
- return Read(addr, ssPeers);
+ return DeserializeFileDB(pathAddr, addr);
}
bool CAddrDB::Read(CAddrMan& addr, CDataStream& ssPeers)
{
- unsigned char pchMsgTmp[4];
- try {
- // de-serialize file header (network specific magic number) and ..
- ssPeers >> 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
- ssPeers >> addr;
- }
- catch (const std::exception& e) {
- // de-serialization has failed, ensure addrman is left in a clean state
+ bool ret = DeserializeDB(ssPeers, addr, false);
+ if (!ret) {
+ // Ensure addrman is left in a clean state
addr.Clear();
- return error("%s: Deserialize or I/O error - %s", __func__, e.what());
}
-
- return true;
+ return ret;
}
diff --git a/src/addrdb.h b/src/addrdb.h
index ab985b10cb..d930de204d 100644
--- a/src/addrdb.h
+++ b/src/addrdb.h
@@ -6,11 +6,11 @@
#ifndef BITCOIN_ADDRDB_H
#define BITCOIN_ADDRDB_H
+#include "fs.h"
#include "serialize.h"
#include <string>
#include <map>
-#include <boost/filesystem/path.hpp>
class CSubNet;
class CAddrMan;
@@ -37,7 +37,7 @@ public:
SetNull();
}
- CBanEntry(int64_t nCreateTimeIn)
+ explicit CBanEntry(int64_t nCreateTimeIn)
{
SetNull();
nCreateTime = nCreateTimeIn;
@@ -61,7 +61,7 @@ public:
banReason = BanReasonUnknown;
}
- std::string banReasonToString()
+ std::string banReasonToString() const
{
switch (banReason) {
case BanReasonNodeMisbehaving:
@@ -80,19 +80,19 @@ typedef std::map<CSubNet, CBanEntry> banmap_t;
class CAddrDB
{
private:
- boost::filesystem::path pathAddr;
+ fs::path pathAddr;
public:
CAddrDB();
bool Write(const CAddrMan& addr);
bool Read(CAddrMan& addr);
- bool Read(CAddrMan& addr, CDataStream& ssPeers);
+ static bool Read(CAddrMan& addr, CDataStream& ssPeers);
};
/** Access to the banlist database (banlist.dat) */
class CBanDB
{
private:
- boost::filesystem::path pathBanlist;
+ fs::path pathBanlist;
public:
CBanDB();
bool Write(const banmap_t& banSet);
diff --git a/src/addrman.cpp b/src/addrman.cpp
index 662e931d25..a56bb4f9c1 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -53,14 +53,7 @@ bool CAddrInfo::IsTerrible(int64_t nNow) const
double CAddrInfo::GetChance(int64_t nNow) const
{
double fChance = 1.0;
-
- int64_t nSinceLastSeen = nNow - nTime;
- int64_t nSinceLastTry = nNow - nLastTry;
-
- if (nSinceLastSeen < 0)
- nSinceLastSeen = 0;
- if (nSinceLastTry < 0)
- nSinceLastTry = 0;
+ int64_t nSinceLastTry = std::max<int64_t>(nNow - nLastTry, 0);
// deprioritize very recent attempts away
if (nSinceLastTry < 60 * 10)
@@ -76,13 +69,13 @@ CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int* pnId)
{
std::map<CNetAddr, int>::iterator it = mapAddr.find(addr);
if (it == mapAddr.end())
- return NULL;
+ return nullptr;
if (pnId)
*pnId = (*it).second;
std::map<int, CAddrInfo>::iterator it2 = mapInfo.find((*it).second);
if (it2 != mapInfo.end())
return &(*it2).second;
- return NULL;
+ return nullptr;
}
CAddrInfo* CAddrMan::Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId)
@@ -240,7 +233,7 @@ void CAddrMan::Good_(const CService& addr, int64_t nTime)
if (nUBucket == -1)
return;
- LogPrint("addrman", "Moving %s to tried\n", addr.ToString());
+ LogPrint(BCLog::ADDRMAN, "Moving %s to tried\n", addr.ToString());
// move nId to the tried tables
MakeTried(info, nId);
@@ -255,7 +248,7 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP
int nId;
CAddrInfo* pinfo = Find(addr, &nId);
- // Do not set a penality for a source's self-announcement
+ // Do not set a penalty for a source's self-announcement
if (addr == source) {
nTimePenalty = 0;
}
@@ -358,8 +351,8 @@ CAddrInfo CAddrMan::Select_(bool newOnly)
int nKBucket = RandomInt(ADDRMAN_TRIED_BUCKET_COUNT);
int nKBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE);
while (vvTried[nKBucket][nKBucketPos] == -1) {
- nKBucket = (nKBucket + insecure_rand.rand32()) % ADDRMAN_TRIED_BUCKET_COUNT;
- nKBucketPos = (nKBucketPos + insecure_rand.rand32()) % ADDRMAN_BUCKET_SIZE;
+ nKBucket = (nKBucket + insecure_rand.randbits(ADDRMAN_TRIED_BUCKET_COUNT_LOG2)) % ADDRMAN_TRIED_BUCKET_COUNT;
+ nKBucketPos = (nKBucketPos + insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) % ADDRMAN_BUCKET_SIZE;
}
int nId = vvTried[nKBucket][nKBucketPos];
assert(mapInfo.count(nId) == 1);
@@ -375,8 +368,8 @@ CAddrInfo CAddrMan::Select_(bool newOnly)
int nUBucket = RandomInt(ADDRMAN_NEW_BUCKET_COUNT);
int nUBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE);
while (vvNew[nUBucket][nUBucketPos] == -1) {
- nUBucket = (nUBucket + insecure_rand.rand32()) % ADDRMAN_NEW_BUCKET_COUNT;
- nUBucketPos = (nUBucketPos + insecure_rand.rand32()) % ADDRMAN_BUCKET_SIZE;
+ nUBucket = (nUBucket + insecure_rand.randbits(ADDRMAN_NEW_BUCKET_COUNT_LOG2)) % ADDRMAN_NEW_BUCKET_COUNT;
+ nUBucketPos = (nUBucketPos + insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) % ADDRMAN_BUCKET_SIZE;
}
int nId = vvNew[nUBucket][nUBucketPos];
assert(mapInfo.count(nId) == 1);
diff --git a/src/addrman.h b/src/addrman.h
index 6e5f946bf2..18f3062287 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -136,13 +136,13 @@ public:
*/
//! total number of buckets for tried addresses
-#define ADDRMAN_TRIED_BUCKET_COUNT 256
+#define ADDRMAN_TRIED_BUCKET_COUNT_LOG2 8
//! total number of buckets for new addresses
-#define ADDRMAN_NEW_BUCKET_COUNT 1024
+#define ADDRMAN_NEW_BUCKET_COUNT_LOG2 10
//! maximum allowed number of entries in buckets for new and tried addresses
-#define ADDRMAN_BUCKET_SIZE 64
+#define ADDRMAN_BUCKET_SIZE_LOG2 6
//! over how many buckets entries with tried addresses from a single group (/16 for IPv4) are spread
#define ADDRMAN_TRIED_BUCKETS_PER_GROUP 8
@@ -171,6 +171,11 @@ public:
//! the maximum number of nodes to return in a getaddr call
#define ADDRMAN_GETADDR_MAX 2500
+//! Convenience
+#define ADDRMAN_TRIED_BUCKET_COUNT (1 << ADDRMAN_TRIED_BUCKET_COUNT_LOG2)
+#define ADDRMAN_NEW_BUCKET_COUNT (1 << ADDRMAN_NEW_BUCKET_COUNT_LOG2)
+#define ADDRMAN_BUCKET_SIZE (1 << ADDRMAN_BUCKET_SIZE_LOG2)
+
/**
* Stochastical (IP) address manager
*/
@@ -215,11 +220,11 @@ protected:
FastRandomContext insecure_rand;
//! Find an entry.
- CAddrInfo* Find(const CNetAddr& addr, int *pnId = NULL);
+ CAddrInfo* Find(const CNetAddr& addr, int *pnId = nullptr);
//! find an entry, creating it if necessary.
//! nTime and nServices of the found node are updated, if necessary.
- CAddrInfo* Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId = NULL);
+ CAddrInfo* Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId = nullptr);
//! Swap two elements in vRandom.
void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2);
@@ -442,7 +447,7 @@ public:
}
}
if (nLost + nLostUnk > 0) {
- LogPrint("addrman", "addrman lost %i new and %i tried addresses due to collisions\n", nLostUnk, nLost);
+ LogPrint(BCLog::ADDRMAN, "addrman lost %i new and %i tried addresses due to collisions\n", nLostUnk, nLost);
}
Check();
@@ -467,6 +472,8 @@ public:
nTried = 0;
nNew = 0;
nLastGood = 1; //Initially at 1 so that "never" is strictly worse.
+ mapInfo.clear();
+ mapAddr.clear();
}
CAddrMan()
@@ -507,8 +514,9 @@ public:
Check();
fRet |= Add_(addr, source, nTimePenalty);
Check();
- if (fRet)
- LogPrint("addrman", "Added %s from %s: %i tried, %i new\n", addr.ToStringIPPort(), source.ToString(), nTried, nNew);
+ if (fRet) {
+ LogPrint(BCLog::ADDRMAN, "Added %s from %s: %i tried, %i new\n", addr.ToStringIPPort(), source.ToString(), nTried, nNew);
+ }
return fRet;
}
@@ -521,8 +529,9 @@ public:
for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++)
nAdd += Add_(*it, source, nTimePenalty) ? 1 : 0;
Check();
- if (nAdd)
- LogPrint("addrman", "Added %i addresses from %s: %i tried, %i new\n", nAdd, source.ToString(), nTried, nNew);
+ if (nAdd) {
+ LogPrint(BCLog::ADDRMAN, "Added %i addresses from %s: %i tried, %i new\n", nAdd, source.ToString(), nTried, nNew);
+ }
return nAdd > 0;
}
diff --git a/src/amount.h b/src/amount.h
index 93060f7193..2bd367cba2 100644
--- a/src/amount.h
+++ b/src/amount.h
@@ -6,10 +6,7 @@
#ifndef BITCOIN_AMOUNT_H
#define BITCOIN_AMOUNT_H
-#include "serialize.h"
-
-#include <stdlib.h>
-#include <string>
+#include <stdint.h>
/** Amount in satoshis (Can be negative) */
typedef int64_t CAmount;
@@ -17,8 +14,6 @@ typedef int64_t CAmount;
static const CAmount COIN = 100000000;
static const CAmount CENT = 1000000;
-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
@@ -31,42 +26,4 @@ extern const std::string CURRENCY_UNIT;
static const CAmount MAX_MONEY = 21000000 * COIN;
inline bool MoneyRange(const CAmount& nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
-/**
- * Fee rate in satoshis per kilobyte: CAmount / kB
- */
-class CFeeRate
-{
-private:
- CAmount nSatoshisPerK; // unit is satoshis-per-1,000-bytes
-public:
- /** Fee rate of 0 satoshis per kB */
- CFeeRate() : nSatoshisPerK(0) { }
- explicit CFeeRate(const CAmount& _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) { }
- /** Constructor for a fee rate in satoshis per kB. The size in bytes must not exceed (2^63 - 1)*/
- CFeeRate(const CAmount& nFeePaid, size_t nBytes);
- CFeeRate(const CFeeRate& other) { nSatoshisPerK = other.nSatoshisPerK; }
- /**
- * Return the fee in satoshis for the given size in bytes.
- */
- CAmount GetFee(size_t nBytes) const;
- /**
- * Return the fee in satoshis for a size of 1000 bytes
- */
- CAmount GetFeePerK() const { return GetFee(1000); }
- friend bool operator<(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK < b.nSatoshisPerK; }
- friend bool operator>(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK > b.nSatoshisPerK; }
- friend bool operator==(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK == b.nSatoshisPerK; }
- friend bool operator<=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK <= b.nSatoshisPerK; }
- friend bool operator>=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK >= b.nSatoshisPerK; }
- CFeeRate& operator+=(const CFeeRate& a) { nSatoshisPerK += a.nSatoshisPerK; return *this; }
- std::string ToString() const;
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action) {
- READWRITE(nSatoshisPerK);
- }
-};
-
#endif // BITCOIN_AMOUNT_H
diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp
index f9f2d19e68..b4952af6f4 100644
--- a/src/arith_uint256.cpp
+++ b/src/arith_uint256.cpp
@@ -15,6 +15,8 @@
template <unsigned int BITS>
base_uint<BITS>::base_uint(const std::string& str)
{
+ static_assert(BITS/32 > 0 && BITS%32 == 0, "Template parameter BITS must be a positive multiple of 32.");
+
SetHex(str);
}
@@ -173,9 +175,9 @@ unsigned int base_uint<BITS>::bits() const
{
for (int pos = WIDTH - 1; pos >= 0; pos--) {
if (pn[pos]) {
- for (int bits = 31; bits > 0; bits--) {
- if (pn[pos] & 1 << bits)
- return 32 * pos + bits + 1;
+ for (int nbits = 31; nbits > 0; nbits--) {
+ if (pn[pos] & 1 << nbits)
+ return 32 * pos + nbits + 1;
}
return 32 * pos + 1;
}
diff --git a/src/arith_uint256.h b/src/arith_uint256.h
index 0f6b3d4fba..5fd4fe96cf 100644
--- a/src/arith_uint256.h
+++ b/src/arith_uint256.h
@@ -31,12 +31,16 @@ public:
base_uint()
{
+ static_assert(BITS/32 > 0 && BITS%32 == 0, "Template parameter BITS must be a positive multiple of 32.");
+
for (int i = 0; i < WIDTH; i++)
pn[i] = 0;
}
base_uint(const base_uint& b)
{
+ static_assert(BITS/32 > 0 && BITS%32 == 0, "Template parameter BITS must be a positive multiple of 32.");
+
for (int i = 0; i < WIDTH; i++)
pn[i] = b.pn[i];
}
@@ -50,6 +54,8 @@ public:
base_uint(uint64_t b)
{
+ static_assert(BITS/32 > 0 && BITS%32 == 0, "Template parameter BITS must be a positive multiple of 32.");
+
pn[0] = (unsigned int)b;
pn[1] = (unsigned int)(b >> 32);
for (int i = 2; i < WIDTH; i++)
@@ -174,7 +180,7 @@ public:
{
// prefix operator
int i = 0;
- while (++pn[i] == 0 && i < WIDTH-1)
+ while (i < WIDTH && ++pn[i] == 0)
i++;
return *this;
}
@@ -191,7 +197,7 @@ public:
{
// prefix operator
int i = 0;
- while (--pn[i] == (uint32_t)-1 && i < WIDTH-1)
+ while (i < WIDTH && --pn[i] == (uint32_t)-1)
i++;
return *this;
}
@@ -244,7 +250,7 @@ public:
uint64_t GetLow64() const
{
- assert(WIDTH >= 2);
+ static_assert(WIDTH >= 2, "Assertion WIDTH >= 2 failed (WIDTH = BITS / 32). BITS is a template parameter.");
return pn[0] | (uint64_t)pn[1] << 32;
}
};
@@ -277,7 +283,7 @@ public:
* complexities of the sign bit and using base 256 are probably an
* implementation accident.
*/
- arith_uint256& SetCompact(uint32_t nCompact, bool *pfNegative = NULL, bool *pfOverflow = NULL);
+ arith_uint256& SetCompact(uint32_t nCompact, bool *pfNegative = nullptr, bool *pfOverflow = nullptr);
uint32_t GetCompact(bool fNegative = false) const;
friend uint256 ArithToUint256(const arith_uint256 &);
diff --git a/src/base58.cpp b/src/base58.cpp
index e2f475bb7f..c2cc5d979f 100644
--- a/src/base58.cpp
+++ b/src/base58.cpp
@@ -4,17 +4,20 @@
#include "base58.h"
+#include "bech32.h"
#include "hash.h"
+#include "script/script.h"
#include "uint256.h"
+#include "utilstrencodings.h"
-#include <assert.h>
-#include <stdint.h>
-#include <string.h>
-#include <vector>
-#include <string>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
+#include <algorithm>
+#include <assert.h>
+#include <string.h>
+
+
/** All alphanumeric characters except for "0", "I", "O", and "l" */
static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
@@ -37,7 +40,7 @@ bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch)
while (*psz && !isspace(*psz)) {
// Decode base58 character
const char* ch = strchr(pszBase58, *psz);
- if (ch == NULL)
+ if (ch == nullptr)
return false;
// Apply "b256 = b256 * 58 + ch".
int carry = ch - pszBase58;
@@ -110,7 +113,7 @@ std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
std::string EncodeBase58(const std::vector<unsigned char>& vch)
{
- return EncodeBase58(&vch[0], &vch[0] + vch.size());
+ return EncodeBase58(vch.data(), vch.data() + vch.size());
}
bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet)
@@ -134,7 +137,7 @@ bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet)
vchRet.clear();
return false;
}
- // re-calculate the checksum, insure it matches the included 4-byte checksum
+ // re-calculate the checksum, ensure it matches the included 4-byte checksum
uint256 hash = Hash(vchRet.begin(), vchRet.end() - 4);
if (memcmp(&hash, &vchRet.end()[-4], 4) != 0) {
vchRet.clear();
@@ -160,7 +163,7 @@ void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const
vchVersion = vchVersionIn;
vchData.resize(nSize);
if (!vchData.empty())
- memcpy(&vchData[0], pdata, nSize);
+ memcpy(vchData.data(), pdata, nSize);
}
void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const unsigned char* pbegin, const unsigned char* pend)
@@ -180,8 +183,8 @@ bool CBase58Data::SetString(const char* psz, unsigned int nVersionBytes)
vchVersion.assign(vchTemp.begin(), vchTemp.begin() + nVersionBytes);
vchData.resize(vchTemp.size() - nVersionBytes);
if (!vchData.empty())
- memcpy(&vchData[0], &vchTemp[nVersionBytes], vchData.size());
- memory_cleanse(&vchTemp[0], vchTemp.size());
+ memcpy(vchData.data(), vchTemp.data() + nVersionBytes, vchData.size());
+ memory_cleanse(vchTemp.data(), vchTemp.size());
return true;
}
@@ -212,79 +215,113 @@ int CBase58Data::CompareTo(const CBase58Data& b58) const
namespace
{
-class CBitcoinAddressVisitor : public boost::static_visitor<bool>
+class DestinationEncoder : public boost::static_visitor<std::string>
{
private:
- CBitcoinAddress* addr;
+ const CChainParams& m_params;
public:
- CBitcoinAddressVisitor(CBitcoinAddress* addrIn) : addr(addrIn) {}
-
- bool operator()(const CKeyID& id) const { return addr->Set(id); }
- bool operator()(const CScriptID& id) const { return addr->Set(id); }
- bool operator()(const CNoDestination& no) const { return false; }
-};
-
-} // anon namespace
-
-bool CBitcoinAddress::Set(const CKeyID& id)
-{
- SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20);
- return true;
-}
+ DestinationEncoder(const CChainParams& params) : m_params(params) {}
-bool CBitcoinAddress::Set(const CScriptID& id)
-{
- SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20);
- return true;
-}
+ std::string operator()(const CKeyID& id) const
+ {
+ std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
+ data.insert(data.end(), id.begin(), id.end());
+ return EncodeBase58Check(data);
+ }
-bool CBitcoinAddress::Set(const CTxDestination& dest)
-{
- return boost::apply_visitor(CBitcoinAddressVisitor(this), dest);
-}
+ std::string operator()(const CScriptID& id) const
+ {
+ std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
+ data.insert(data.end(), id.begin(), id.end());
+ return EncodeBase58Check(data);
+ }
-bool CBitcoinAddress::IsValid() const
-{
- return IsValid(Params());
-}
+ std::string operator()(const WitnessV0KeyHash& id) const
+ {
+ std::vector<unsigned char> data = {0};
+ ConvertBits<8, 5, true>(data, id.begin(), id.end());
+ return bech32::Encode(m_params.Bech32HRP(), data);
+ }
-bool CBitcoinAddress::IsValid(const CChainParams& params) const
-{
- bool fCorrectSize = vchData.size() == 20;
- bool fKnownVersion = vchVersion == params.Base58Prefix(CChainParams::PUBKEY_ADDRESS) ||
- vchVersion == params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
- return fCorrectSize && fKnownVersion;
-}
+ std::string operator()(const WitnessV0ScriptHash& id) const
+ {
+ std::vector<unsigned char> data = {0};
+ ConvertBits<8, 5, true>(data, id.begin(), id.end());
+ return bech32::Encode(m_params.Bech32HRP(), data);
+ }
-CTxDestination CBitcoinAddress::Get() const
-{
- if (!IsValid())
- return CNoDestination();
- uint160 id;
- memcpy(&id, &vchData[0], 20);
- if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
- return CKeyID(id);
- else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS))
- return CScriptID(id);
- else
- return CNoDestination();
-}
+ std::string operator()(const WitnessUnknown& id) const
+ {
+ if (id.version < 1 || id.version > 16 || id.length < 2 || id.length > 40) {
+ return {};
+ }
+ std::vector<unsigned char> data = {(unsigned char)id.version};
+ ConvertBits<8, 5, true>(data, id.program, id.program + id.length);
+ return bech32::Encode(m_params.Bech32HRP(), data);
+ }
-bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const
-{
- if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
- return false;
- uint160 id;
- memcpy(&id, &vchData[0], 20);
- keyID = CKeyID(id);
- return true;
-}
+ std::string operator()(const CNoDestination& no) const { return {}; }
+};
-bool CBitcoinAddress::IsScript() const
+CTxDestination DecodeDestination(const std::string& str, const CChainParams& params)
{
- return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS);
+ std::vector<unsigned char> data;
+ uint160 hash;
+ if (DecodeBase58Check(str, data)) {
+ // base58-encoded Bitcoin addresses.
+ // Public-key-hash-addresses have version 0 (or 111 testnet).
+ // The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
+ const std::vector<unsigned char>& pubkey_prefix = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
+ if (data.size() == hash.size() + pubkey_prefix.size() && std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) {
+ std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin());
+ return CKeyID(hash);
+ }
+ // Script-hash-addresses have version 5 (or 196 testnet).
+ // The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
+ const std::vector<unsigned char>& script_prefix = params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
+ if (data.size() == hash.size() + script_prefix.size() && std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) {
+ std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin());
+ return CScriptID(hash);
+ }
+ }
+ data.clear();
+ auto bech = bech32::Decode(str);
+ if (bech.second.size() > 0 && bech.first == params.Bech32HRP()) {
+ // Bech32 decoding
+ int version = bech.second[0]; // The first 5 bit symbol is the witness version (0-16)
+ // The rest of the symbols are converted witness program bytes.
+ if (ConvertBits<5, 8, false>(data, bech.second.begin() + 1, bech.second.end())) {
+ if (version == 0) {
+ {
+ WitnessV0KeyHash keyid;
+ if (data.size() == keyid.size()) {
+ std::copy(data.begin(), data.end(), keyid.begin());
+ return keyid;
+ }
+ }
+ {
+ WitnessV0ScriptHash scriptid;
+ if (data.size() == scriptid.size()) {
+ std::copy(data.begin(), data.end(), scriptid.begin());
+ return scriptid;
+ }
+ }
+ return CNoDestination();
+ }
+ if (version > 16 || data.size() < 2 || data.size() > 40) {
+ return CNoDestination();
+ }
+ WitnessUnknown unk;
+ unk.version = version;
+ std::copy(data.begin(), data.end(), unk.program);
+ unk.length = data.size();
+ return unk;
+ }
+ }
+ return CNoDestination();
}
+} // namespace
void CBitcoinSecret::SetKey(const CKey& vchSecret)
{
@@ -318,3 +355,23 @@ bool CBitcoinSecret::SetString(const std::string& strSecret)
{
return SetString(strSecret.c_str());
}
+
+std::string EncodeDestination(const CTxDestination& dest)
+{
+ return boost::apply_visitor(DestinationEncoder(Params()), dest);
+}
+
+CTxDestination DecodeDestination(const std::string& str)
+{
+ return DecodeDestination(str, Params());
+}
+
+bool IsValidDestinationString(const std::string& str, const CChainParams& params)
+{
+ return IsValidDestination(DecodeDestination(str, params));
+}
+
+bool IsValidDestinationString(const std::string& str)
+{
+ return IsValidDestinationString(str, Params());
+}
diff --git a/src/base58.h b/src/base58.h
index cccebc9e0e..9dc4234248 100644
--- a/src/base58.h
+++ b/src/base58.h
@@ -17,7 +17,6 @@
#include "chainparams.h"
#include "key.h"
#include "pubkey.h"
-#include "script/script.h"
#include "script/standard.h"
#include "support/allocators/zeroafterfree.h"
@@ -26,7 +25,7 @@
/**
* Encode a byte sequence as a base58-encoded string.
- * pbegin and pend cannot be NULL, unless both are.
+ * pbegin and pend cannot be nullptr, unless both are.
*/
std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend);
@@ -38,7 +37,7 @@ std::string EncodeBase58(const std::vector<unsigned char>& vch);
/**
* Decode a base58-encoded string (psz) into a byte vector (vchRet).
* return true if decoding is successful.
- * psz cannot be NULL.
+ * psz cannot be nullptr.
*/
bool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet);
@@ -95,30 +94,6 @@ public:
bool operator> (const CBase58Data& b58) const { return CompareTo(b58) > 0; }
};
-/** base58-encoded Bitcoin addresses.
- * Public-key-hash-addresses have version 0 (or 111 testnet).
- * The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
- * Script-hash-addresses have version 5 (or 196 testnet).
- * The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
- */
-class CBitcoinAddress : public CBase58Data {
-public:
- bool Set(const CKeyID &id);
- bool Set(const CScriptID &id);
- bool Set(const CTxDestination &dest);
- bool IsValid() const;
- bool IsValid(const CChainParams &params) const;
-
- CBitcoinAddress() {}
- CBitcoinAddress(const CTxDestination &dest) { Set(dest); }
- CBitcoinAddress(const std::string& strAddress) { SetString(strAddress); }
- CBitcoinAddress(const char* pszAddress) { SetString(pszAddress); }
-
- CTxDestination Get() const;
- bool GetKeyID(CKeyID &keyID) const;
- bool IsScript() const;
-};
-
/**
* A base58-encoded secret key
*/
@@ -147,8 +122,8 @@ public:
K GetKey() {
K ret;
if (vchData.size() == Size) {
- //if base58 encouded data not holds a ext key, return a !IsValid() key
- ret.Decode(&vchData[0]);
+ // If base58 encoded data does not hold an ext key, return a !IsValid() key
+ ret.Decode(vchData.data());
}
return ret;
}
@@ -167,4 +142,9 @@ public:
typedef CBitcoinExtKeyBase<CExtKey, BIP32_EXTKEY_SIZE, CChainParams::EXT_SECRET_KEY> CBitcoinExtKey;
typedef CBitcoinExtKeyBase<CExtPubKey, BIP32_EXTKEY_SIZE, CChainParams::EXT_PUBLIC_KEY> CBitcoinExtPubKey;
+std::string EncodeDestination(const CTxDestination& dest);
+CTxDestination DecodeDestination(const std::string& str);
+bool IsValidDestinationString(const std::string& str);
+bool IsValidDestinationString(const std::string& str, const CChainParams& params);
+
#endif // BITCOIN_BASE58_H
diff --git a/src/bech32.cpp b/src/bech32.cpp
new file mode 100644
index 0000000000..573eac58bb
--- /dev/null
+++ b/src/bech32.cpp
@@ -0,0 +1,191 @@
+// Copyright (c) 2017 Pieter Wuille
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "bech32.h"
+
+namespace
+{
+
+typedef std::vector<uint8_t> data;
+
+/** The Bech32 character set for encoding. */
+const char* CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
+
+/** The Bech32 character set for decoding. */
+const int8_t CHARSET_REV[128] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,
+ -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
+ 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
+ -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
+ 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
+};
+
+/** Concatenate two byte arrays. */
+data Cat(data x, const data& y)
+{
+ x.insert(x.end(), y.begin(), y.end());
+ return x;
+}
+
+/** This function will compute what 6 5-bit values to XOR into the last 6 input values, in order to
+ * make the checksum 0. These 6 values are packed together in a single 30-bit integer. The higher
+ * bits correspond to earlier values. */
+uint32_t PolyMod(const data& v)
+{
+ // The input is interpreted as a list of coefficients of a polynomial over F = GF(32), with an
+ // implicit 1 in front. If the input is [v0,v1,v2,v3,v4], that polynomial is v(x) =
+ // 1*x^5 + v0*x^4 + v1*x^3 + v2*x^2 + v3*x + v4. The implicit 1 guarantees that
+ // [v0,v1,v2,...] has a distinct checksum from [0,v0,v1,v2,...].
+
+ // The output is a 30-bit integer whose 5-bit groups are the coefficients of the remainder of
+ // v(x) mod g(x), where g(x) is the Bech32 generator,
+ // x^6 + {29}x^5 + {22}x^4 + {20}x^3 + {21}x^2 + {29}x + {18}. g(x) is chosen in such a way
+ // that the resulting code is a BCH code, guaranteeing detection of up to 3 errors within a
+ // window of 1023 characters. Among the various possible BCH codes, one was selected to in
+ // fact guarantee detection of up to 4 errors within a window of 89 characters.
+
+ // Note that the coefficients are elements of GF(32), here represented as decimal numbers
+ // between {}. In this finite field, addition is just XOR of the corresponding numbers. For
+ // example, {27} + {13} = {27 ^ 13} = {22}. Multiplication is more complicated, and requires
+ // treating the bits of values themselves as coefficients of a polynomial over a smaller field,
+ // GF(2), and multiplying those polynomials mod a^5 + a^3 + 1. For example, {5} * {26} =
+ // (a^2 + 1) * (a^4 + a^3 + a) = (a^4 + a^3 + a) * a^2 + (a^4 + a^3 + a) = a^6 + a^5 + a^4 + a
+ // = a^3 + 1 (mod a^5 + a^3 + 1) = {9}.
+
+ // During the course of the loop below, `c` contains the bitpacked coefficients of the
+ // polynomial constructed from just the values of v that were processed so far, mod g(x). In
+ // the above example, `c` initially corresponds to 1 mod (x), and after processing 2 inputs of
+ // v, it corresponds to x^2 + v0*x + v1 mod g(x). As 1 mod g(x) = 1, that is the starting value
+ // for `c`.
+ uint32_t c = 1;
+ for (auto v_i : v) {
+ // We want to update `c` to correspond to a polynomial with one extra term. If the initial
+ // value of `c` consists of the coefficients of c(x) = f(x) mod g(x), we modify it to
+ // correspond to c'(x) = (f(x) * x + v_i) mod g(x), where v_i is the next input to
+ // process. Simplifying:
+ // c'(x) = (f(x) * x + v_i) mod g(x)
+ // ((f(x) mod g(x)) * x + v_i) mod g(x)
+ // (c(x) * x + v_i) mod g(x)
+ // If c(x) = c0*x^5 + c1*x^4 + c2*x^3 + c3*x^2 + c4*x + c5, we want to compute
+ // c'(x) = (c0*x^5 + c1*x^4 + c2*x^3 + c3*x^2 + c4*x + c5) * x + v_i mod g(x)
+ // = c0*x^6 + c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i mod g(x)
+ // = c0*(x^6 mod g(x)) + c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i
+ // If we call (x^6 mod g(x)) = k(x), this can be written as
+ // c'(x) = (c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i) + c0*k(x)
+
+ // First, determine the value of c0:
+ uint8_t c0 = c >> 25;
+
+ // Then compute c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i:
+ c = ((c & 0x1ffffff) << 5) ^ v_i;
+
+ // Finally, for each set bit n in c0, conditionally add {2^n}k(x):
+ if (c0 & 1) c ^= 0x3b6a57b2; // k(x) = {29}x^5 + {22}x^4 + {20}x^3 + {21}x^2 + {29}x + {18}
+ if (c0 & 2) c ^= 0x26508e6d; // {2}k(x) = {19}x^5 + {5}x^4 + x^3 + {3}x^2 + {19}x + {13}
+ if (c0 & 4) c ^= 0x1ea119fa; // {4}k(x) = {15}x^5 + {10}x^4 + {2}x^3 + {6}x^2 + {15}x + {26}
+ if (c0 & 8) c ^= 0x3d4233dd; // {8}k(x) = {30}x^5 + {20}x^4 + {4}x^3 + {12}x^2 + {30}x + {29}
+ if (c0 & 16) c ^= 0x2a1462b3; // {16}k(x) = {21}x^5 + x^4 + {8}x^3 + {24}x^2 + {21}x + {19}
+ }
+ return c;
+}
+
+/** Convert to lower case. */
+inline unsigned char LowerCase(unsigned char c)
+{
+ return (c >= 'A' && c <= 'Z') ? (c - 'A') + 'a' : c;
+}
+
+/** Expand a HRP for use in checksum computation. */
+data ExpandHRP(const std::string& hrp)
+{
+ data ret;
+ ret.reserve(hrp.size() + 90);
+ ret.resize(hrp.size() * 2 + 1);
+ for (size_t i = 0; i < hrp.size(); ++i) {
+ unsigned char c = hrp[i];
+ ret[i] = c >> 5;
+ ret[i + hrp.size() + 1] = c & 0x1f;
+ }
+ ret[hrp.size()] = 0;
+ return ret;
+}
+
+/** Verify a checksum. */
+bool VerifyChecksum(const std::string& hrp, const data& values)
+{
+ // PolyMod computes what value to xor into the final values to make the checksum 0. However,
+ // if we required that the checksum was 0, it would be the case that appending a 0 to a valid
+ // list of values would result in a new valid list. For that reason, Bech32 requires the
+ // resulting checksum to be 1 instead.
+ return PolyMod(Cat(ExpandHRP(hrp), values)) == 1;
+}
+
+/** Create a checksum. */
+data CreateChecksum(const std::string& hrp, const data& values)
+{
+ data enc = Cat(ExpandHRP(hrp), values);
+ enc.resize(enc.size() + 6); // Append 6 zeroes
+ uint32_t mod = PolyMod(enc) ^ 1; // Determine what to XOR into those 6 zeroes.
+ data ret(6);
+ for (size_t i = 0; i < 6; ++i) {
+ // Convert the 5-bit groups in mod to checksum values.
+ ret[i] = (mod >> (5 * (5 - i))) & 31;
+ }
+ return ret;
+}
+
+} // namespace
+
+namespace bech32
+{
+
+/** Encode a Bech32 string. */
+std::string Encode(const std::string& hrp, const data& values) {
+ data checksum = CreateChecksum(hrp, values);
+ data combined = Cat(values, checksum);
+ std::string ret = hrp + '1';
+ ret.reserve(ret.size() + combined.size());
+ for (auto c : combined) {
+ ret += CHARSET[c];
+ }
+ return ret;
+}
+
+/** Decode a Bech32 string. */
+std::pair<std::string, data> Decode(const std::string& str) {
+ bool lower = false, upper = false;
+ for (size_t i = 0; i < str.size(); ++i) {
+ unsigned char c = str[i];
+ if (c < 33 || c > 126) return {};
+ if (c >= 'a' && c <= 'z') lower = true;
+ if (c >= 'A' && c <= 'Z') upper = true;
+ }
+ if (lower && upper) return {};
+ size_t pos = str.rfind('1');
+ if (str.size() > 90 || pos == str.npos || pos == 0 || pos + 7 > str.size()) {
+ return {};
+ }
+ data values(str.size() - 1 - pos);
+ for (size_t i = 0; i < str.size() - 1 - pos; ++i) {
+ unsigned char c = str[i + pos + 1];
+ int8_t rev = (c < 33 || c > 126) ? -1 : CHARSET_REV[c];
+ if (rev == -1) {
+ return {};
+ }
+ values[i] = rev;
+ }
+ std::string hrp;
+ for (size_t i = 0; i < pos; ++i) {
+ hrp += LowerCase(str[i]);
+ }
+ if (!VerifyChecksum(hrp, values)) {
+ return {};
+ }
+ return {hrp, data(values.begin(), values.end() - 6)};
+}
+
+} // namespace bech32
diff --git a/src/bech32.h b/src/bech32.h
new file mode 100644
index 0000000000..7ef7b22213
--- /dev/null
+++ b/src/bech32.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2017 Pieter Wuille
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+// Bech32 is a string encoding format used in newer address types.
+// The output consists of a human-readable part (alphanumeric), a
+// separator character (1), and a base32 data section, the last
+// 6 characters of which are a checksum.
+//
+// For more information, see BIP 173.
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+namespace bech32
+{
+
+/** Encode a Bech32 string. Returns the empty string in case of failure. */
+std::string Encode(const std::string& hrp, const std::vector<uint8_t>& values);
+
+/** Decode a Bech32 string. Returns (hrp, data). Empty hrp means failure. */
+std::pair<std::string, std::vector<uint8_t>> Decode(const std::string& str);
+
+} // namespace bech32
diff --git a/src/bench/base58.cpp b/src/bench/base58.cpp
index 3319c179bf..65e27a615d 100644
--- a/src/bench/base58.cpp
+++ b/src/bench/base58.cpp
@@ -7,34 +7,37 @@
#include "validation.h"
#include "base58.h"
+#include <array>
#include <vector>
#include <string>
static void Base58Encode(benchmark::State& state)
{
- unsigned char buff[32] = {
- 17, 79, 8, 99, 150, 189, 208, 162, 22, 23, 203, 163, 36, 58, 147,
- 227, 139, 2, 215, 100, 91, 38, 11, 141, 253, 40, 117, 21, 16, 90,
- 200, 24
+ static const std::array<unsigned char, 32> buff = {
+ {
+ 17, 79, 8, 99, 150, 189, 208, 162, 22, 23, 203, 163, 36, 58, 147,
+ 227, 139, 2, 215, 100, 91, 38, 11, 141, 253, 40, 117, 21, 16, 90,
+ 200, 24
+ }
};
- unsigned char* b = buff;
while (state.KeepRunning()) {
- EncodeBase58(b, b + 32);
+ EncodeBase58(buff.begin(), buff.end());
}
}
static void Base58CheckEncode(benchmark::State& state)
{
- unsigned char buff[32] = {
- 17, 79, 8, 99, 150, 189, 208, 162, 22, 23, 203, 163, 36, 58, 147,
- 227, 139, 2, 215, 100, 91, 38, 11, 141, 253, 40, 117, 21, 16, 90,
- 200, 24
+ static const std::array<unsigned char, 32> buff = {
+ {
+ 17, 79, 8, 99, 150, 189, 208, 162, 22, 23, 203, 163, 36, 58, 147,
+ 227, 139, 2, 215, 100, 91, 38, 11, 141, 253, 40, 117, 21, 16, 90,
+ 200, 24
+ }
};
- unsigned char* b = buff;
std::vector<unsigned char> vch;
- vch.assign(b, b + 32);
+ vch.assign(buff.begin(), buff.end());
while (state.KeepRunning()) {
EncodeBase58Check(vch);
}
diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp
index 1bd9d06b80..7b307d6f42 100644
--- a/src/bench/bench.cpp
+++ b/src/bench/bench.cpp
@@ -5,21 +5,25 @@
#include "bench.h"
#include "perf.h"
+#include <assert.h>
#include <iostream>
#include <iomanip>
#include <sys/time.h>
-std::map<std::string, benchmark::BenchFunction> benchmark::BenchRunner::benchmarks;
+benchmark::BenchRunner::BenchmarkMap &benchmark::BenchRunner::benchmarks() {
+ static std::map<std::string, benchmark::BenchFunction> benchmarks_map;
+ return benchmarks_map;
+}
static double gettimedouble(void) {
struct timeval tv;
- gettimeofday(&tv, NULL);
+ gettimeofday(&tv, nullptr);
return tv.tv_usec * 0.000001 + tv.tv_sec;
}
benchmark::BenchRunner::BenchRunner(std::string name, benchmark::BenchFunction func)
{
- benchmarks.insert(std::make_pair(name, func));
+ benchmarks().insert(std::make_pair(name, func));
}
void
@@ -29,12 +33,9 @@ benchmark::BenchRunner::RunAll(double elapsedTimeForOne)
std::cout << "#Benchmark" << "," << "count" << "," << "min" << "," << "max" << "," << "average" << ","
<< "min_cycles" << "," << "max_cycles" << "," << "average_cycles" << "\n";
- for (std::map<std::string,benchmark::BenchFunction>::iterator it = benchmarks.begin();
- it != benchmarks.end(); ++it) {
-
- State state(it->first, elapsedTimeForOne);
- benchmark::BenchFunction& func = it->second;
- func(state);
+ for (const auto &p: benchmarks()) {
+ State state(p.first, elapsedTimeForOne);
+ p.second(state);
}
perf_fini();
}
@@ -54,13 +55,13 @@ bool benchmark::State::KeepRunning()
else {
now = gettimedouble();
double elapsed = now - lastTime;
- double elapsedOne = elapsed * countMaskInv;
+ double elapsedOne = elapsed / (countMask + 1);
if (elapsedOne < minTime) minTime = elapsedOne;
if (elapsedOne > maxTime) maxTime = elapsedOne;
// We only use relative values, so don't have to handle 64-bit wrap-around specially
nowCycles = perf_cpucycles();
- uint64_t elapsedOneCycles = (nowCycles - lastCycles) * countMaskInv;
+ uint64_t elapsedOneCycles = (nowCycles - lastCycles) / (countMask + 1);
if (elapsedOneCycles < minCycles) minCycles = elapsedOneCycles;
if (elapsedOneCycles > maxCycles) maxCycles = elapsedOneCycles;
@@ -68,7 +69,6 @@ bool benchmark::State::KeepRunning()
// If the execution was much too fast (1/128th of maxElapsed), increase the count mask by 8x and restart timing.
// The restart avoids including the overhead of this code in the measurement.
countMask = ((countMask<<3)|7) & ((1LL<<60)-1);
- countMaskInv = 1./(countMask+1);
count = 0;
minTime = std::numeric_limits<double>::max();
maxTime = std::numeric_limits<double>::min();
@@ -80,7 +80,6 @@ bool benchmark::State::KeepRunning()
uint64_t newCountMask = ((countMask<<1)|1) & ((1LL<<60)-1);
if ((count & newCountMask)==0) {
countMask = newCountMask;
- countMaskInv = 1./(countMask+1);
}
}
}
@@ -92,11 +91,14 @@ bool benchmark::State::KeepRunning()
--count;
+ assert(count != 0 && "count == 0 => (now == 0 && beginTime == 0) => return above");
+
// Output results
double average = (now-beginTime)/count;
int64_t averageCycles = (nowCycles-beginCycles)/count;
std::cout << std::fixed << std::setprecision(15) << name << "," << count << "," << minTime << "," << maxTime << "," << average << ","
<< minCycles << "," << maxCycles << "," << averageCycles << "\n";
+ std::cout.copyfmt(std::ios(nullptr));
return false;
}
diff --git a/src/bench/bench.h b/src/bench/bench.h
index 80dad6a8ef..79109eaa56 100644
--- a/src/bench/bench.h
+++ b/src/bench/bench.h
@@ -5,16 +5,17 @@
#ifndef BITCOIN_BENCH_BENCH_H
#define BITCOIN_BENCH_BENCH_H
+#include <functional>
+#include <limits>
#include <map>
#include <string>
-#include <boost/function.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/stringize.hpp>
// Simple micro-benchmarking framework; API mostly matches a subset of the Google Benchmark
// framework (see https://github.com/google/benchmark)
-// Wny not use the Google Benchmark framework? Because adding Yet Another Dependency
+// Why not use the Google Benchmark framework? Because adding Yet Another Dependency
// (that uses cmake as its build system and has lots of features we don't need) isn't
// worth it.
@@ -40,7 +41,7 @@ namespace benchmark {
std::string name;
double maxElapsed;
double beginTime;
- double lastTime, minTime, maxTime, countMaskInv;
+ double lastTime, minTime, maxTime;
uint64_t count;
uint64_t countMask;
uint64_t beginCycles;
@@ -54,16 +55,16 @@ namespace benchmark {
minCycles = std::numeric_limits<uint64_t>::max();
maxCycles = std::numeric_limits<uint64_t>::min();
countMask = 1;
- countMaskInv = 1./(countMask + 1);
}
bool KeepRunning();
};
- typedef boost::function<void(State&)> BenchFunction;
+ typedef std::function<void(State&)> BenchFunction;
class BenchRunner
{
- static std::map<std::string, BenchFunction> benchmarks;
+ typedef std::map<std::string, BenchFunction> BenchmarkMap;
+ static BenchmarkMap &benchmarks();
public:
BenchRunner(std::string name, BenchFunction func);
diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp
index 61a0b31aed..37fd772435 100644
--- a/src/bench/bench_bitcoin.cpp
+++ b/src/bench/bench_bitcoin.cpp
@@ -4,13 +4,17 @@
#include "bench.h"
+#include "crypto/sha256.h"
#include "key.h"
#include "validation.h"
#include "util.h"
+#include "random.h"
int
main(int argc, char** argv)
{
+ SHA256AutoDetect();
+ RandomInit();
ECC_Start();
SetupEnvironment();
fPrintToDebugLog = false; // don't want to write to debug.log file
diff --git a/src/bench/ccoins_caching.cpp b/src/bench/ccoins_caching.cpp
index 1e8e3d462f..5aab3381fd 100644
--- a/src/bench/ccoins_caching.cpp
+++ b/src/bench/ccoins_caching.cpp
@@ -35,14 +35,14 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
dummyTransactions[0].vout[0].scriptPubKey << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG;
dummyTransactions[0].vout[1].nValue = 50 * CENT;
dummyTransactions[0].vout[1].scriptPubKey << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG;
- coinsRet.ModifyCoins(dummyTransactions[0].GetHash())->FromTx(dummyTransactions[0], 0);
+ AddCoins(coinsRet, dummyTransactions[0], 0);
dummyTransactions[1].vout.resize(2);
dummyTransactions[1].vout[0].nValue = 21 * CENT;
dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID());
dummyTransactions[1].vout[1].nValue = 22 * CENT;
dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID());
- coinsRet.ModifyCoins(dummyTransactions[1].GetHash())->FromTx(dummyTransactions[1], 0);
+ AddCoins(coinsRet, dummyTransactions[1], 0);
return dummyTransactions;
}
diff --git a/src/bench/checkblock.cpp b/src/bench/checkblock.cpp
index 230e4ca773..7bb1b93668 100644
--- a/src/bench/checkblock.cpp
+++ b/src/bench/checkblock.cpp
@@ -11,7 +11,7 @@
namespace block_bench {
#include "bench/data/block413567.raw.h"
-}
+} // namespace block_bench
// These are the two major time-sinks which happen after we have fully received
// a block off the wire, but before we can relay the block on to peers using
@@ -22,7 +22,7 @@ static void DeserializeBlockTest(benchmark::State& state)
CDataStream stream((const char*)block_bench::block413567,
(const char*)&block_bench::block413567[sizeof(block_bench::block413567)],
SER_NETWORK, PROTOCOL_VERSION);
- char a;
+ char a = '\0';
stream.write(&a, 1); // Prevent compaction
while (state.KeepRunning()) {
@@ -37,10 +37,10 @@ static void DeserializeAndCheckBlockTest(benchmark::State& state)
CDataStream stream((const char*)block_bench::block413567,
(const char*)&block_bench::block413567[sizeof(block_bench::block413567)],
SER_NETWORK, PROTOCOL_VERSION);
- char a;
+ char a = '\0';
stream.write(&a, 1); // Prevent compaction
- Consensus::Params params = Params(CBaseChainParams::MAIN).GetConsensus();
+ const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);
while (state.KeepRunning()) {
CBlock block; // Note that CBlock caches its checked state, so we need to recreate it here
@@ -48,7 +48,7 @@ static void DeserializeAndCheckBlockTest(benchmark::State& state)
assert(stream.Rewind(sizeof(block_bench::block413567)));
CValidationState validationState;
- assert(CheckBlock(block, validationState, params));
+ assert(CheckBlock(block, validationState, chainParams->GetConsensus()));
}
}
diff --git a/src/bench/checkqueue.cpp b/src/bench/checkqueue.cpp
new file mode 100644
index 0000000000..b7ae5c2d57
--- /dev/null
+++ b/src/bench/checkqueue.cpp
@@ -0,0 +1,103 @@
+// 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 "bench.h"
+#include "util.h"
+#include "validation.h"
+#include "checkqueue.h"
+#include "prevector.h"
+#include <vector>
+#include <boost/thread/thread.hpp>
+#include "random.h"
+
+
+// This Benchmark tests the CheckQueue with the lightest
+// weight Checks, so it should make any lock contention
+// particularly visible
+static const int MIN_CORES = 2;
+static const size_t BATCHES = 101;
+static const size_t BATCH_SIZE = 30;
+static const int PREVECTOR_SIZE = 28;
+static const int QUEUE_BATCH_SIZE = 128;
+static void CCheckQueueSpeed(benchmark::State& state)
+{
+ struct FakeJobNoWork {
+ bool operator()()
+ {
+ return true;
+ }
+ void swap(FakeJobNoWork& x){};
+ };
+ CCheckQueue<FakeJobNoWork> queue {QUEUE_BATCH_SIZE};
+ boost::thread_group tg;
+ for (auto x = 0; x < std::max(MIN_CORES, GetNumCores()); ++x) {
+ tg.create_thread([&]{queue.Thread();});
+ }
+ while (state.KeepRunning()) {
+ CCheckQueueControl<FakeJobNoWork> control(&queue);
+
+ // We call Add a number of times to simulate the behavior of adding
+ // a block of transactions at once.
+
+ std::vector<std::vector<FakeJobNoWork>> vBatches(BATCHES);
+ for (auto& vChecks : vBatches) {
+ vChecks.resize(BATCH_SIZE);
+ }
+ for (auto& vChecks : vBatches) {
+ // We can't make vChecks in the inner loop because we want to measure
+ // the cost of getting the memory to each thread and we might get the same
+ // memory
+ control.Add(vChecks);
+ }
+ // control waits for completion by RAII, but
+ // it is done explicitly here for clarity
+ control.Wait();
+ }
+ tg.interrupt_all();
+ tg.join_all();
+}
+
+// This Benchmark tests the CheckQueue with a slightly realistic workload,
+// where checks all contain a prevector that is indirect 50% of the time
+// and there is a little bit of work done between calls to Add.
+static void CCheckQueueSpeedPrevectorJob(benchmark::State& state)
+{
+ struct PrevectorJob {
+ prevector<PREVECTOR_SIZE, uint8_t> p;
+ PrevectorJob(){
+ }
+ explicit PrevectorJob(FastRandomContext& insecure_rand){
+ p.resize(insecure_rand.randrange(PREVECTOR_SIZE*2));
+ }
+ bool operator()()
+ {
+ return true;
+ }
+ void swap(PrevectorJob& x){p.swap(x.p);};
+ };
+ CCheckQueue<PrevectorJob> queue {QUEUE_BATCH_SIZE};
+ boost::thread_group tg;
+ for (auto x = 0; x < std::max(MIN_CORES, GetNumCores()); ++x) {
+ tg.create_thread([&]{queue.Thread();});
+ }
+ while (state.KeepRunning()) {
+ // Make insecure_rand here so that each iteration is identical.
+ FastRandomContext insecure_rand(true);
+ CCheckQueueControl<PrevectorJob> control(&queue);
+ std::vector<std::vector<PrevectorJob>> vBatches(BATCHES);
+ for (auto& vChecks : vBatches) {
+ vChecks.reserve(BATCH_SIZE);
+ for (size_t x = 0; x < BATCH_SIZE; ++x)
+ vChecks.emplace_back(insecure_rand);
+ control.Add(vChecks);
+ }
+ // control waits for completion by RAII, but
+ // it is done explicitly here for clarity
+ control.Wait();
+ }
+ tg.interrupt_all();
+ tg.join_all();
+}
+BENCHMARK(CCheckQueueSpeed);
+BENCHMARK(CCheckQueueSpeedPrevectorJob);
diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp
index 29fbd34631..f8956508f6 100644
--- a/src/bench/coin_selection.cpp
+++ b/src/bench/coin_selection.cpp
@@ -5,7 +5,6 @@
#include "bench.h"
#include "wallet/wallet.h"
-#include <boost/foreach.hpp>
#include <set>
static void addCoin(const CAmount& nValue, const CWallet& wallet, std::vector<COutput>& vCoins)
@@ -20,7 +19,7 @@ static void addCoin(const CAmount& nValue, const CWallet& wallet, std::vector<CO
CWalletTx* wtx = new CWalletTx(&wallet, MakeTransactionRef(std::move(tx)));
int nAge = 6 * 24;
- COutput output(wtx, nInput, nAge, true, true);
+ COutput output(wtx, nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
vCoins.push_back(output);
}
@@ -39,7 +38,7 @@ static void CoinSelection(benchmark::State& state)
while (state.KeepRunning()) {
// Empty wallet.
- BOOST_FOREACH (COutput output, vCoins)
+ for (COutput output : vCoins)
delete output.tx;
vCoins.clear();
@@ -48,7 +47,7 @@ static void CoinSelection(benchmark::State& state)
addCoin(1000 * COIN, wallet, vCoins);
addCoin(3 * COIN, wallet, vCoins);
- std::set<std::pair<const CWalletTx*, unsigned int> > setCoinsRet;
+ std::set<CInputCoin> setCoinsRet;
CAmount nValueRet;
bool success = wallet.SelectCoinsMinConf(1003 * COIN, 1, 6, 0, vCoins, setCoinsRet, nValueRet);
assert(success);
diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp
index 737d3572ae..410a08e512 100644
--- a/src/bench/crypto_hash.cpp
+++ b/src/bench/crypto_hash.cpp
@@ -7,6 +7,7 @@
#include "bench.h"
#include "bloom.h"
#include "hash.h"
+#include "random.h"
#include "uint256.h"
#include "utiltime.h"
#include "crypto/ripemd160.h"
@@ -46,7 +47,7 @@ static void SHA256_32b(benchmark::State& state)
std::vector<uint8_t> in(32,0);
while (state.KeepRunning()) {
for (int i = 0; i < 1000000; i++) {
- CSHA256().Write(in.data(), in.size()).Finalize(&in[0]);
+ CSHA256().Write(in.data(), in.size()).Finalize(in.data());
}
}
}
@@ -69,6 +70,28 @@ static void SipHash_32b(benchmark::State& state)
}
}
+static void FastRandom_32bit(benchmark::State& state)
+{
+ FastRandomContext rng(true);
+ uint32_t x = 0;
+ while (state.KeepRunning()) {
+ for (int i = 0; i < 1000000; i++) {
+ x += rng.rand32();
+ }
+ }
+}
+
+static void FastRandom_1bit(benchmark::State& state)
+{
+ FastRandomContext rng(true);
+ uint32_t x = 0;
+ while (state.KeepRunning()) {
+ for (int i = 0; i < 1000000; i++) {
+ x += rng.randbool();
+ }
+ }
+}
+
BENCHMARK(RIPEMD160);
BENCHMARK(SHA1);
BENCHMARK(SHA256);
@@ -76,3 +99,5 @@ BENCHMARK(SHA512);
BENCHMARK(SHA256_32b);
BENCHMARK(SipHash_32b);
+BENCHMARK(FastRandom_32bit);
+BENCHMARK(FastRandom_1bit);
diff --git a/src/bench/lockedpool.cpp b/src/bench/lockedpool.cpp
index 5df5b1ac6e..c6a05567be 100644
--- a/src/bench/lockedpool.cpp
+++ b/src/bench/lockedpool.cpp
@@ -13,7 +13,7 @@
#define BITER 5000
#define MSIZE 2048
-static void LockedPool(benchmark::State& state)
+static void BenchLockedPool(benchmark::State& state)
{
void *synth_base = reinterpret_cast<void*>(0x08000000);
const size_t synth_size = 1024*1024;
@@ -21,14 +21,14 @@ static void LockedPool(benchmark::State& state)
std::vector<void*> addr;
for (int x=0; x<ASIZE; ++x)
- addr.push_back(0);
+ addr.push_back(nullptr);
uint32_t s = 0x12345678;
while (state.KeepRunning()) {
for (int x=0; x<BITER; ++x) {
int idx = s & (addr.size()-1);
if (s & 0x80000000) {
b.free(addr[idx]);
- addr[idx] = 0;
+ addr[idx] = nullptr;
} else if(!addr[idx]) {
addr[idx] = b.alloc((s >> 16) & (MSIZE-1));
}
@@ -43,5 +43,5 @@ static void LockedPool(benchmark::State& state)
addr.clear();
}
-BENCHMARK(LockedPool);
+BENCHMARK(BenchLockedPool);
diff --git a/src/bench/mempool_eviction.cpp b/src/bench/mempool_eviction.cpp
index 5790d51a82..073bbde016 100644
--- a/src/bench/mempool_eviction.cpp
+++ b/src/bench/mempool_eviction.cpp
@@ -12,14 +12,13 @@
static void AddTx(const CTransaction& tx, const CAmount& nFee, CTxMemPool& pool)
{
int64_t nTime = 0;
- double dPriority = 10.0;
unsigned int nHeight = 1;
bool spendsCoinbase = false;
unsigned int sigOpCost = 4;
LockPoints lp;
pool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(
- MakeTransactionRef(tx), nFee, nTime, dPriority, nHeight,
- tx.GetValueOut(), spendsCoinbase, sigOpCost, lp));
+ MakeTransactionRef(tx), nFee, nTime, nHeight,
+ spendsCoinbase, sigOpCost, lp));
}
// Right now this is only testing eviction performance in an extremely small
@@ -97,7 +96,7 @@ static void MempoolEviction(benchmark::State& state)
tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
tx7.vout[1].nValue = 10 * COIN;
- CTxMemPool pool(CFeeRate(1000));
+ CTxMemPool pool;
while (state.KeepRunning()) {
AddTx(tx1, 10000LL, pool);
diff --git a/src/bench/perf.cpp b/src/bench/perf.cpp
index 1f43e5d3ac..a549ec29ea 100644
--- a/src/bench/perf.cpp
+++ b/src/bench/perf.cpp
@@ -6,7 +6,7 @@
#if defined(__i386__) || defined(__x86_64__)
-/* These architectures support quering the cycle counter
+/* These architectures support querying the cycle counter
* from user space, no need for any syscall overhead.
*/
void perf_init(void) { }
diff --git a/src/bench/prevector_destructor.cpp b/src/bench/prevector_destructor.cpp
new file mode 100644
index 0000000000..55af3de4fe
--- /dev/null
+++ b/src/bench/prevector_destructor.cpp
@@ -0,0 +1,36 @@
+// Copyright (c) 2015-2017 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 "bench.h"
+#include "prevector.h"
+
+static void PrevectorDestructor(benchmark::State& state)
+{
+ while (state.KeepRunning()) {
+ for (auto x = 0; x < 1000; ++x) {
+ prevector<28, unsigned char> t0;
+ prevector<28, unsigned char> t1;
+ t0.resize(28);
+ t1.resize(29);
+ }
+ }
+}
+
+static void PrevectorClear(benchmark::State& state)
+{
+
+ while (state.KeepRunning()) {
+ for (auto x = 0; x < 1000; ++x) {
+ prevector<28, unsigned char> t0;
+ prevector<28, unsigned char> t1;
+ t0.resize(28);
+ t0.clear();
+ t1.resize(29);
+ t0.clear();
+ }
+ }
+}
+
+BENCHMARK(PrevectorDestructor);
+BENCHMARK(PrevectorClear);
diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp
index 23bbadc88d..ef7381c120 100644
--- a/src/bench/verify_script.cpp
+++ b/src/bench/verify_script.cpp
@@ -11,6 +11,8 @@
#include "script/sign.h"
#include "streams.h"
+#include <array>
+
// FIXME: Dedup with BuildCreditingTransaction in test/script_tests.cpp.
static CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey)
{
@@ -55,8 +57,12 @@ static void VerifyScriptBench(benchmark::State& state)
// Keypair.
CKey key;
- const unsigned char vchKey[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
- key.Set(vchKey, vchKey + 32, false);
+ static const std::array<unsigned char, 32> vchKey = {
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
+ }
+ };
+ key.Set(vchKey.begin(), vchKey.end(), false);
CPubKey pubkey = key.GetPubKey();
uint160 pubkeyHash;
CHash160().Write(pubkey.begin(), pubkey.size()).Finalize(pubkeyHash.begin());
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 1c330cf5ea..e21a269221 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -9,12 +9,12 @@
#include "chainparamsbase.h"
#include "clientversion.h"
+#include "fs.h"
#include "rpc/client.h"
#include "rpc/protocol.h"
#include "util.h"
#include "utilstrencodings.h"
-#include <boost/filesystem/operations.hpp>
#include <stdio.h>
#include <event2/buffer.h>
@@ -30,20 +30,25 @@ static const int CONTINUE_EXECUTION=-1;
std::string HelpMessageCli()
{
+ const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN);
+ const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET);
std::string strUsage;
strUsage += HelpMessageGroup(_("Options:"));
strUsage += HelpMessageOpt("-?", _("This help message"));
strUsage += HelpMessageOpt("-conf=<file>", strprintf(_("Specify configuration file (default: %s)"), BITCOIN_CONF_FILENAME));
strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory"));
+ strUsage += HelpMessageOpt("-getinfo", _("Get general information from the remote server. Note that unlike server-side RPC calls, the results of -getinfo is the result of multiple non-atomic requests. Some entries in the result may represent results from different states (e.g. wallet balance may be as of a different block from the chain state reported)"));
AppendParamsHelpMessages(strUsage);
strUsage += HelpMessageOpt("-named", strprintf(_("Pass named instead of positional arguments (default: %s)"), DEFAULT_NAMED));
strUsage += HelpMessageOpt("-rpcconnect=<ip>", strprintf(_("Send commands to node running on <ip> (default: %s)"), DEFAULT_RPCCONNECT));
- strUsage += HelpMessageOpt("-rpcport=<port>", strprintf(_("Connect to JSON-RPC on <port> (default: %u or testnet: %u)"), BaseParams(CBaseChainParams::MAIN).RPCPort(), BaseParams(CBaseChainParams::TESTNET).RPCPort()));
+ strUsage += HelpMessageOpt("-rpcport=<port>", strprintf(_("Connect to JSON-RPC on <port> (default: %u or testnet: %u)"), defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort()));
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 += HelpMessageOpt("-rpcclienttimeout=<n>", strprintf(_("Timeout during HTTP requests (default: %d)"), DEFAULT_HTTP_CLIENT_TIMEOUT));
- strUsage += HelpMessageOpt("-stdin", _("Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases)"));
+ strUsage += HelpMessageOpt("-rpcclienttimeout=<n>", strprintf(_("Timeout in seconds during HTTP requests, or 0 for no timeout. (default: %d)"), DEFAULT_HTTP_CLIENT_TIMEOUT));
+ strUsage += HelpMessageOpt("-stdinrpcpass", strprintf(_("Read RPC password from standard input as a single line. When combined with -stdin, the first line from standard input is used for the RPC password.")));
+ strUsage += HelpMessageOpt("-stdin", _("Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases). When combined with -stdinrpcpass, the first line from standard input is used for the RPC password."));
+ strUsage += HelpMessageOpt("-rpcwallet=<walletname>", _("Send RPC for non-default wallet on RPC server (argument is wallet filename in bitcoind directory, required if bitcoind/-Qt runs with multiple wallets)"));
return strUsage;
}
@@ -76,10 +81,10 @@ static int AppInitRPC(int argc, char* argv[])
//
// Parameters
//
- ParseParameters(argc, argv);
- if (argc<2 || IsArgSet("-?") || IsArgSet("-h") || IsArgSet("-help") || IsArgSet("-version")) {
+ gArgs.ParseParameters(argc, argv);
+ if (argc<2 || gArgs.IsArgSet("-?") || gArgs.IsArgSet("-h") || gArgs.IsArgSet("-help") || gArgs.IsArgSet("-version")) {
std::string strUsage = strprintf(_("%s RPC client version"), _(PACKAGE_NAME)) + " " + FormatFullVersion() + "\n";
- if (!IsArgSet("-version")) {
+ if (!gArgs.IsArgSet("-version")) {
strUsage += "\n" + _("Usage:") + "\n" +
" bitcoin-cli [options] <command> [params] " + strprintf(_("Send command to %s"), _(PACKAGE_NAME)) + "\n" +
" bitcoin-cli [options] -named <command> [name=value] ... " + strprintf(_("Send command to %s (with named arguments)"), _(PACKAGE_NAME)) + "\n" +
@@ -96,12 +101,12 @@ static int AppInitRPC(int argc, char* argv[])
}
return EXIT_SUCCESS;
}
- if (!boost::filesystem::is_directory(GetDataDir(false))) {
- fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", GetArg("-datadir", "").c_str());
+ if (!fs::is_directory(GetDataDir(false))) {
+ fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
return EXIT_FAILURE;
}
try {
- ReadConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME));
+ gArgs.ReadConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME));
} catch (const std::exception& e) {
fprintf(stderr,"Error reading configuration file: %s\n", e.what());
return EXIT_FAILURE;
@@ -113,7 +118,7 @@ static int AppInitRPC(int argc, char* argv[])
fprintf(stderr, "Error: %s\n", e.what());
return EXIT_FAILURE;
}
- if (GetBoolArg("-rpcssl", false))
+ if (gArgs.GetBoolArg("-rpcssl", false))
{
fprintf(stderr, "Error: SSL mode for RPC (-rpcssl) is no longer supported.\n");
return EXIT_FAILURE;
@@ -158,8 +163,8 @@ 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: the
+ if (req == nullptr) {
+ /* If req is nullptr, it means an error occurred while connecting: the
* error code will have been passed to http_error_cb.
*/
reply->status = 0;
@@ -187,21 +192,116 @@ static void http_error_cb(enum evhttp_request_error err, void *ctx)
}
#endif
-UniValue CallRPC(const std::string& strMethod, const UniValue& params)
+/** Class that handles the conversion from a command-line to a JSON-RPC request,
+ * as well as converting back to a JSON object that can be shown as result.
+ */
+class BaseRequestHandler
{
- std::string host = GetArg("-rpcconnect", DEFAULT_RPCCONNECT);
- int port = GetArg("-rpcport", BaseParams().RPCPort());
+public:
+ virtual UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) = 0;
+ virtual UniValue ProcessReply(const UniValue &batch_in) = 0;
+};
+
+/** Process getinfo requests */
+class GetinfoRequestHandler: public BaseRequestHandler
+{
+public:
+ const int ID_NETWORKINFO = 0;
+ const int ID_BLOCKCHAININFO = 1;
+ const int ID_WALLETINFO = 2;
+
+ /** Create a simulated `getinfo` request. */
+ UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) override
+ {
+ UniValue result(UniValue::VARR);
+ result.push_back(JSONRPCRequestObj("getnetworkinfo", NullUniValue, ID_NETWORKINFO));
+ result.push_back(JSONRPCRequestObj("getblockchaininfo", NullUniValue, ID_BLOCKCHAININFO));
+ result.push_back(JSONRPCRequestObj("getwalletinfo", NullUniValue, ID_WALLETINFO));
+ return result;
+ }
+
+ /** Collect values from the batch and form a simulated `getinfo` reply. */
+ UniValue ProcessReply(const UniValue &batch_in) override
+ {
+ UniValue result(UniValue::VOBJ);
+ std::vector<UniValue> batch = JSONRPCProcessBatchReply(batch_in, 3);
+ // Errors in getnetworkinfo() and getblockchaininfo() are fatal, pass them on
+ // getwalletinfo() is allowed to fail in case there is no wallet.
+ if (!batch[ID_NETWORKINFO]["error"].isNull()) {
+ return batch[ID_NETWORKINFO];
+ }
+ if (!batch[ID_BLOCKCHAININFO]["error"].isNull()) {
+ return batch[ID_BLOCKCHAININFO];
+ }
+ result.pushKV("version", batch[ID_NETWORKINFO]["result"]["version"]);
+ result.pushKV("protocolversion", batch[ID_NETWORKINFO]["result"]["protocolversion"]);
+ if (!batch[ID_WALLETINFO].isNull()) {
+ result.pushKV("walletversion", batch[ID_WALLETINFO]["result"]["walletversion"]);
+ result.pushKV("balance", batch[ID_WALLETINFO]["result"]["balance"]);
+ }
+ result.pushKV("blocks", batch[ID_BLOCKCHAININFO]["result"]["blocks"]);
+ result.pushKV("timeoffset", batch[ID_NETWORKINFO]["result"]["timeoffset"]);
+ result.pushKV("connections", batch[ID_NETWORKINFO]["result"]["connections"]);
+ result.pushKV("proxy", batch[ID_NETWORKINFO]["result"]["networks"][0]["proxy"]);
+ result.pushKV("difficulty", batch[ID_BLOCKCHAININFO]["result"]["difficulty"]);
+ result.pushKV("testnet", UniValue(batch[ID_BLOCKCHAININFO]["result"]["chain"].get_str() == "test"));
+ if (!batch[ID_WALLETINFO].isNull()) {
+ result.pushKV("walletversion", batch[ID_WALLETINFO]["result"]["walletversion"]);
+ result.pushKV("balance", batch[ID_WALLETINFO]["result"]["balance"]);
+ result.pushKV("keypoololdest", batch[ID_WALLETINFO]["result"]["keypoololdest"]);
+ result.pushKV("keypoolsize", batch[ID_WALLETINFO]["result"]["keypoolsize"]);
+ if (!batch[ID_WALLETINFO]["result"]["unlocked_until"].isNull()) {
+ result.pushKV("unlocked_until", batch[ID_WALLETINFO]["result"]["unlocked_until"]);
+ }
+ result.pushKV("paytxfee", batch[ID_WALLETINFO]["result"]["paytxfee"]);
+ }
+ result.pushKV("relayfee", batch[ID_NETWORKINFO]["result"]["relayfee"]);
+ result.pushKV("warnings", batch[ID_NETWORKINFO]["result"]["warnings"]);
+ return JSONRPCReplyObj(result, NullUniValue, 1);
+ }
+};
+
+/** Process default single requests */
+class DefaultRequestHandler: public BaseRequestHandler {
+public:
+ UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) override
+ {
+ UniValue params;
+ if(gArgs.GetBoolArg("-named", DEFAULT_NAMED)) {
+ params = RPCConvertNamedValues(method, args);
+ } else {
+ params = RPCConvertValues(method, args);
+ }
+ return JSONRPCRequestObj(method, params, 1);
+ }
+
+ UniValue ProcessReply(const UniValue &reply) override
+ {
+ return reply.get_obj();
+ }
+};
+
+static UniValue CallRPC(BaseRequestHandler *rh, const std::string& strMethod, const std::vector<std::string>& args)
+{
+ std::string host;
+ // In preference order, we choose the following for the port:
+ // 1. -rpcport
+ // 2. port in -rpcconnect (ie following : in ipv4 or ]: in ipv6)
+ // 3. default port for chain
+ int port = BaseParams().RPCPort();
+ SplitHostPort(gArgs.GetArg("-rpcconnect", DEFAULT_RPCCONNECT), port, host);
+ port = gArgs.GetArg("-rpcport", port);
// Obtain event base
raii_event_base base = obtain_event_base();
// Synchronously look up hostname
raii_evhttp_connection evcon = obtain_evhttp_connection_base(base.get(), host, port);
- evhttp_connection_set_timeout(evcon.get(), GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT));
+ evhttp_connection_set_timeout(evcon.get(), gArgs.GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT));
HTTPReply response;
raii_evhttp_request req = obtain_evhttp_request(http_request_done, (void*)&response);
- if (req == NULL)
+ if (req == nullptr)
throw std::runtime_error("create http request failed");
#if LIBEVENT_VERSION_NUMBER >= 0x02010300
evhttp_request_set_error_cb(req.get(), http_error_cb);
@@ -209,16 +309,16 @@ UniValue CallRPC(const std::string& strMethod, const UniValue& params)
// Get credentials
std::string strRPCUserColonPass;
- if (GetArg("-rpcpassword", "") == "") {
+ if (gArgs.GetArg("-rpcpassword", "") == "") {
// Try fall back to cookie-based authentication if no password is provided
if (!GetAuthCookie(&strRPCUserColonPass)) {
throw std::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(GetArg("-conf", BITCOIN_CONF_FILENAME)).string().c_str()));
+ _("Could not locate RPC credentials. No authentication cookie could be found, and RPC password is not set. See -rpcpassword and -stdinrpcpass. Configuration file: (%s)"),
+ GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)).string().c_str()));
}
} else {
- strRPCUserColonPass = GetArg("-rpcuser", "") + ":" + GetArg("-rpcpassword", "");
+ strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" + gArgs.GetArg("-rpcpassword", "");
}
struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req.get());
@@ -228,12 +328,25 @@ UniValue CallRPC(const std::string& strMethod, const UniValue& params)
evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str());
// Attach request data
- std::string strRequest = JSONRPCRequestObj(strMethod, params, 1).write() + "\n";
+ std::string strRequest = rh->PrepareRequest(strMethod, args).write() + "\n";
struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req.get());
assert(output_buffer);
evbuffer_add(output_buffer, strRequest.data(), strRequest.size());
- int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST, "/");
+ // check if we should use a special wallet endpoint
+ std::string endpoint = "/";
+ std::string walletName = gArgs.GetArg("-rpcwallet", "");
+ if (!walletName.empty()) {
+ char *encodedURI = evhttp_uriencode(walletName.c_str(), walletName.size(), false);
+ if (encodedURI) {
+ endpoint = "/wallet/"+ std::string(encodedURI);
+ free(encodedURI);
+ }
+ else {
+ throw CConnectionFailed("uri-encode failed");
+ }
+ }
+ int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST, endpoint.c_str());
req.release(); // ownership moved to evcon in above call
if (r != 0) {
throw CConnectionFailed("send http request failed");
@@ -254,7 +367,7 @@ UniValue CallRPC(const std::string& strMethod, const UniValue& params)
UniValue valReply(UniValue::VSTR);
if (!valReply.read(response.body))
throw std::runtime_error("couldn't parse reply from server");
- const UniValue& reply = valReply.get_obj();
+ const UniValue reply = rh->ProcessReply(valReply);
if (reply.empty())
throw std::runtime_error("expected reply to have result, error and id properties");
@@ -271,30 +384,40 @@ int CommandLineRPC(int argc, char *argv[])
argc--;
argv++;
}
+ std::string rpcPass;
+ if (gArgs.GetBoolArg("-stdinrpcpass", false)) {
+ if (!std::getline(std::cin, rpcPass)) {
+ throw std::runtime_error("-stdinrpcpass specified but failed to read from standard input");
+ }
+ gArgs.ForceSetArg("-rpcpassword", rpcPass);
+ }
std::vector<std::string> args = std::vector<std::string>(&argv[1], &argv[argc]);
- if (GetBoolArg("-stdin", false)) {
+ if (gArgs.GetBoolArg("-stdin", false)) {
// Read one arg per line from stdin and append
std::string line;
- while (std::getline(std::cin,line))
+ while (std::getline(std::cin, line)) {
args.push_back(line);
+ }
}
- if (args.size() < 1)
- throw std::runtime_error("too few parameters (need at least command)");
- std::string strMethod = args[0];
- args.erase(args.begin()); // Remove trailing method name from arguments vector
-
- UniValue params;
- if(GetBoolArg("-named", DEFAULT_NAMED)) {
- params = RPCConvertNamedValues(strMethod, args);
+ std::unique_ptr<BaseRequestHandler> rh;
+ std::string method;
+ if (gArgs.GetBoolArg("-getinfo", false)) {
+ rh.reset(new GetinfoRequestHandler());
+ method = "";
} else {
- params = RPCConvertValues(strMethod, args);
+ rh.reset(new DefaultRequestHandler());
+ if (args.size() < 1) {
+ throw std::runtime_error("too few parameters (need at least command)");
+ }
+ method = args[0];
+ args.erase(args.begin()); // Remove trailing method name from arguments vector
}
// Execute and handle connection failures with -rpcwait
- const bool fWait = GetBoolArg("-rpcwait", false);
+ const bool fWait = gArgs.GetBoolArg("-rpcwait", false);
do {
try {
- const UniValue reply = CallRPC(strMethod, params);
+ const UniValue reply = CallRPC(rh.get(), method, args);
// Parse reply
const UniValue& result = find_value(reply, "result");
@@ -315,6 +438,10 @@ int CommandLineRPC(int argc, char *argv[])
if (errMsg.isStr())
strPrint += "error message:\n"+errMsg.get_str();
+
+ if (errCode.isNum() && errCode.get_int() == RPC_WALLET_NOT_SPECIFIED) {
+ strPrint += "\nTry adding \"-rpcwallet=<filename>\" option to bitcoin-cli command line.";
+ }
}
} else {
// Result
@@ -344,7 +471,7 @@ int CommandLineRPC(int argc, char *argv[])
nRet = EXIT_FAILURE;
}
catch (...) {
- PrintExceptionContinue(NULL, "CommandLineRPC()");
+ PrintExceptionContinue(nullptr, "CommandLineRPC()");
throw;
}
@@ -371,7 +498,7 @@ int main(int argc, char* argv[])
PrintExceptionContinue(&e, "AppInitRPC()");
return EXIT_FAILURE;
} catch (...) {
- PrintExceptionContinue(NULL, "AppInitRPC()");
+ PrintExceptionContinue(nullptr, "AppInitRPC()");
return EXIT_FAILURE;
}
@@ -382,7 +509,7 @@ int main(int argc, char* argv[])
catch (const std::exception& e) {
PrintExceptionContinue(&e, "CommandLineRPC()");
} catch (...) {
- PrintExceptionContinue(NULL, "CommandLineRPC()");
+ PrintExceptionContinue(nullptr, "CommandLineRPC()");
}
return ret;
}
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 3c3646523a..e4f44435ba 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -13,6 +13,7 @@
#include "core_io.h"
#include "keystore.h"
#include "policy/policy.h"
+#include "policy/rbf.h"
#include "primitives/transaction.h"
#include "script/script.h"
#include "script/sign.h"
@@ -24,7 +25,6 @@
#include <stdio.h>
#include <boost/algorithm/string.hpp>
-#include <boost/assign/list_of.hpp>
static bool fCreateBlank;
static std::map<std::string,UniValue> registers;
@@ -39,7 +39,7 @@ static int AppInitRawTx(int argc, char* argv[])
//
// Parameters
//
- ParseParameters(argc, argv);
+ gArgs.ParseParameters(argc, argv);
// Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
try {
@@ -49,9 +49,9 @@ static int AppInitRawTx(int argc, char* argv[])
return EXIT_FAILURE;
}
- fCreateBlank = GetBoolArg("-create", false);
+ fCreateBlank = gArgs.GetBoolArg("-create", false);
- if (argc<2 || IsArgSet("-?") || IsArgSet("-h") || IsArgSet("-help"))
+ if (argc<2 || gArgs.IsArgSet("-?") || gArgs.IsArgSet("-h") || gArgs.IsArgSet("-help"))
{
// First part of help message is specific to this utility
std::string strUsage = strprintf(_("%s bitcoin-tx utility version"), _(PACKAGE_NAME)) + " " + FormatFullVersion() + "\n\n" +
@@ -77,6 +77,7 @@ static int AppInitRawTx(int argc, char* argv[])
strUsage += HelpMessageOpt("in=TXID:VOUT(:SEQUENCE_NUMBER)", _("Add input to TX"));
strUsage += HelpMessageOpt("locktime=N", _("Set TX lock time to N"));
strUsage += HelpMessageOpt("nversion=N", _("Set TX version to N"));
+ strUsage += HelpMessageOpt("replaceable(=N)", _("Set RBF opt-in sequence number for input N (if not provided, opt-in all available inputs)"));
strUsage += HelpMessageOpt("outaddr=VALUE:ADDRESS", _("Add address-based output to TX"));
strUsage += HelpMessageOpt("outpubkey=VALUE:PUBKEY[:FLAGS]", _("Add pay-to-pubkey output to TX") + ". " +
_("Optionally add the \"W\" flag to produce a pay-to-witness-pubkey-hash output") + ". " +
@@ -202,6 +203,26 @@ static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal)
tx.nLockTime = (unsigned int) newLocktime;
}
+static void MutateTxRBFOptIn(CMutableTransaction& tx, const std::string& strInIdx)
+{
+ // parse requested index
+ int inIdx = atoi(strInIdx);
+ if (inIdx < 0 || inIdx >= (int)tx.vin.size()) {
+ throw std::runtime_error("Invalid TX input index '" + strInIdx + "'");
+ }
+
+ // set the nSequence to MAX_INT - 2 (= RBF opt in flag)
+ int cnt = 0;
+ for (CTxIn& txin : tx.vin) {
+ if (strInIdx == "" || cnt == inIdx) {
+ if (txin.nSequence > MAX_BIP125_RBF_SEQUENCE) {
+ txin.nSequence = MAX_BIP125_RBF_SEQUENCE;
+ }
+ }
+ ++cnt;
+ }
+}
+
static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInput)
{
std::vector<std::string> vStrInputParts;
@@ -218,7 +239,7 @@ static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInpu
uint256 txid(uint256S(strTxid));
static const unsigned int minTxOutSz = 9;
- static const unsigned int maxVout = MAX_BLOCK_BASE_SIZE / minTxOutSz;
+ static const unsigned int maxVout = MAX_BLOCK_WEIGHT / (WITNESS_SCALE_FACTOR * minTxOutSz);
// extract and validate vout
std::string strVout = vStrInputParts[1];
@@ -242,16 +263,19 @@ static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strIn
std::vector<std::string> vStrInputParts;
boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
+ if (vStrInputParts.size() != 2)
+ throw std::runtime_error("TX output missing or too many separators");
+
// Extract and validate VALUE
CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
// extract and validate ADDRESS
std::string strAddr = vStrInputParts[1];
- CBitcoinAddress addr(strAddr);
- if (!addr.IsValid())
+ CTxDestination destination = DecodeDestination(strAddr);
+ if (!IsValidDestination(destination)) {
throw std::runtime_error("invalid TX output address");
- // build standard output script via GetScriptForDestination()
- CScript scriptPubKey = GetScriptForDestination(addr.Get());
+ }
+ CScript scriptPubKey = GetScriptForDestination(destination);
// construct TxOut, append to transaction output list
CTxOut txout(value, scriptPubKey);
@@ -264,6 +288,9 @@ static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& str
std::vector<std::string> vStrInputParts;
boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
+ if (vStrInputParts.size() < 2 || vStrInputParts.size() > 3)
+ throw std::runtime_error("TX output missing or too many separators");
+
// Extract and validate VALUE
CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
@@ -272,7 +299,6 @@ static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& str
if (!pubkey.IsFullyValid())
throw std::runtime_error("invalid TX output pubkey");
CScript scriptPubKey = GetScriptForRawPubKey(pubkey);
- CBitcoinAddress addr(scriptPubKey);
// Extract and validate FLAGS
bool bSegWit = false;
@@ -284,14 +310,15 @@ static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& str
}
if (bSegWit) {
+ if (!pubkey.IsCompressed()) {
+ throw std::runtime_error("Uncompressed pubkeys are not useable for SegWit outputs");
+ }
// Call GetScriptForWitness() to build a P2WSH scriptPubKey
scriptPubKey = GetScriptForWitness(scriptPubKey);
}
if (bScriptHash) {
- // Get the address for the redeem script, then call
- // GetScriptForDestination() to construct a P2SH scriptPubKey.
- CBitcoinAddress redeemScriptAddr(scriptPubKey);
- scriptPubKey = GetScriptForDestination(redeemScriptAddr.Get());
+ // Get the ID for the script, and then construct a P2SH destination for it.
+ scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey));
}
// construct TxOut, append to transaction output list
@@ -351,14 +378,17 @@ static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& s
CScript scriptPubKey = GetScriptForMultisig(required, pubkeys);
if (bSegWit) {
+ for (CPubKey& pubkey : pubkeys) {
+ if (!pubkey.IsCompressed()) {
+ throw std::runtime_error("Uncompressed pubkeys are not useable for SegWit outputs");
+ }
+ }
// Call GetScriptForWitness() to build a P2WSH scriptPubKey
scriptPubKey = GetScriptForWitness(scriptPubKey);
}
if (bScriptHash) {
- // Get the address for the redeem script, then call
- // GetScriptForDestination() to construct a P2SH scriptPubKey.
- CBitcoinAddress addr(scriptPubKey);
- scriptPubKey = GetScriptForDestination(addr.Get());
+ // Get the ID for the script, and then construct a P2SH destination for it.
+ scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey));
}
// construct TxOut, append to transaction output list
@@ -418,11 +448,10 @@ static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& str
}
if (bSegWit) {
- scriptPubKey = GetScriptForWitness(scriptPubKey);
+ scriptPubKey = GetScriptForWitness(scriptPubKey);
}
if (bScriptHash) {
- CBitcoinAddress addr(scriptPubKey);
- scriptPubKey = GetScriptForDestination(addr.Get());
+ scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey));
}
// construct TxOut, append to transaction output list
@@ -483,22 +512,6 @@ static bool findSighashFlags(int& flags, const std::string& flagStr)
return false;
}
-uint256 ParseHashUO(std::map<std::string,UniValue>& o, std::string strKey)
-{
- if (!o.count(strKey))
- return uint256();
- return ParseHashUV(o[strKey], strKey);
-}
-
-std::vector<unsigned char> ParseHexUO(std::map<std::string,UniValue>& o, std::string strKey)
-{
- if (!o.count(strKey)) {
- std::vector<unsigned char> emptyVec;
- return emptyVec;
- }
- return ParseHexUV(o[strKey], strKey);
-}
-
static CAmount AmountFromValue(const UniValue& value)
{
if (!value.isNum() && !value.isStr())
@@ -556,7 +569,11 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
if (!prevOut.isObject())
throw std::runtime_error("expected prevtxs internal object");
- std::map<std::string,UniValue::VType> types = boost::assign::map_list_of("txid", UniValue::VSTR)("vout",UniValue::VNUM)("scriptPubKey",UniValue::VSTR);
+ std::map<std::string, UniValue::VType> types = {
+ {"txid", UniValue::VSTR},
+ {"vout", UniValue::VNUM},
+ {"scriptPubKey", UniValue::VSTR},
+ };
if (!prevOut.checkObject(types))
throw std::runtime_error("prevtxs internal object typecheck fail");
@@ -566,24 +583,26 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
if (nOut < 0)
throw std::runtime_error("vout must be positive");
+ COutPoint out(txid, nOut);
std::vector<unsigned char> pkData(ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey"));
CScript scriptPubKey(pkData.begin(), pkData.end());
{
- CCoinsModifier coins = view.ModifyCoins(txid);
- if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) {
+ const Coin& coin = view.AccessCoin(out);
+ if (!coin.IsSpent() && coin.out.scriptPubKey != scriptPubKey) {
std::string err("Previous output scriptPubKey mismatch:\n");
- err = err + ScriptToAsmStr(coins->vout[nOut].scriptPubKey) + "\nvs:\n"+
+ err = err + ScriptToAsmStr(coin.out.scriptPubKey) + "\nvs:\n"+
ScriptToAsmStr(scriptPubKey);
throw std::runtime_error(err);
}
- if ((unsigned int)nOut >= coins->vout.size())
- coins->vout.resize(nOut+1);
- coins->vout[nOut].scriptPubKey = scriptPubKey;
- coins->vout[nOut].nValue = 0;
+ Coin newcoin;
+ newcoin.out.scriptPubKey = scriptPubKey;
+ newcoin.out.nValue = 0;
if (prevOut.exists("amount")) {
- coins->vout[nOut].nValue = AmountFromValue(prevOut["amount"]);
+ newcoin.out.nValue = AmountFromValue(prevOut["amount"]);
}
+ newcoin.nHeight = 1;
+ view.AddCoin(out, std::move(newcoin), true);
}
// if redeemScript given and private keys given,
@@ -605,13 +624,13 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
// Sign what we can:
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
CTxIn& txin = mergedTx.vin[i];
- const CCoins* coins = view.AccessCoins(txin.prevout.hash);
- if (!coins || !coins->IsAvailable(txin.prevout.n)) {
+ const Coin& coin = view.AccessCoin(txin.prevout);
+ if (coin.IsSpent()) {
fComplete = false;
continue;
}
- const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey;
- const CAmount& amount = coins->vout[txin.prevout.n].nValue;
+ const CScript& prevPubKey = coin.out.scriptPubKey;
+ const CAmount& amount = coin.out.nValue;
SignatureData sigdata;
// Only sign SIGHASH_SINGLE if there's a corresponding output:
@@ -619,7 +638,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata);
// ... and merge in other signatures:
- BOOST_FOREACH(const CTransaction& txv, txVariants)
+ for (const CTransaction& txv : txVariants)
sigdata = CombineSignatures(prevPubKey, MutableTransactionSignatureChecker(&mergedTx, i, amount), sigdata, DataFromTransaction(txv, i));
UpdateTransaction(mergedTx, i, sigdata);
@@ -657,6 +676,9 @@ static void MutateTx(CMutableTransaction& tx, const std::string& command,
MutateTxVersion(tx, commandVal);
else if (command == "locktime")
MutateTxLocktime(tx, commandVal);
+ else if (command == "replaceable") {
+ MutateTxRBFOptIn(tx, commandVal);
+ }
else if (command == "delin")
MutateTxDelInput(tx, commandVal);
@@ -667,11 +689,13 @@ static void MutateTx(CMutableTransaction& tx, const std::string& command,
MutateTxDelOutput(tx, commandVal);
else if (command == "outaddr")
MutateTxAddOutAddr(tx, commandVal);
- else if (command == "outpubkey")
+ else if (command == "outpubkey") {
+ if (!ecc) { ecc.reset(new Secp256k1Init()); }
MutateTxAddOutPubKey(tx, commandVal);
- else if (command == "outmultisig")
+ } else if (command == "outmultisig") {
+ if (!ecc) { ecc.reset(new Secp256k1Init()); }
MutateTxAddOutMultiSig(tx, commandVal);
- else if (command == "outscript")
+ } else if (command == "outscript")
MutateTxAddOutScript(tx, commandVal);
else if (command == "outdata")
MutateTxAddOutData(tx, commandVal);
@@ -716,9 +740,9 @@ static void OutputTxHex(const CTransaction& tx)
static void OutputTx(const CTransaction& tx)
{
- if (GetBoolArg("-json", false))
+ if (gArgs.GetBoolArg("-json", false))
OutputTxJSON(tx);
- else if (GetBoolArg("-txid", false))
+ else if (gArgs.GetBoolArg("-txid", false))
OutputTxHash(tx);
else
OutputTxHex(tx);
@@ -801,7 +825,7 @@ static int CommandLineRawTx(int argc, char* argv[])
nRet = EXIT_FAILURE;
}
catch (...) {
- PrintExceptionContinue(NULL, "CommandLineRawTx()");
+ PrintExceptionContinue(nullptr, "CommandLineRawTx()");
throw;
}
@@ -824,7 +848,7 @@ int main(int argc, char* argv[])
PrintExceptionContinue(&e, "AppInitRawTx()");
return EXIT_FAILURE;
} catch (...) {
- PrintExceptionContinue(NULL, "AppInitRawTx()");
+ PrintExceptionContinue(nullptr, "AppInitRawTx()");
return EXIT_FAILURE;
}
@@ -835,7 +859,7 @@ int main(int argc, char* argv[])
catch (const std::exception& e) {
PrintExceptionContinue(&e, "CommandLineRawTx()");
} catch (...) {
- PrintExceptionContinue(NULL, "CommandLineRawTx()");
+ PrintExceptionContinue(nullptr, "CommandLineRawTx()");
}
return ret;
}
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index 9bab3a2026..543eba0e69 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -10,6 +10,7 @@
#include "chainparams.h"
#include "clientversion.h"
#include "compat.h"
+#include "fs.h"
#include "rpc/server.h"
#include "init.h"
#include "noui.h"
@@ -19,8 +20,6 @@
#include "httprpc.h"
#include "utilstrencodings.h"
-#include <boost/algorithm/string/predicate.hpp>
-#include <boost/filesystem.hpp>
#include <boost/thread.hpp>
#include <stdio.h>
@@ -72,14 +71,14 @@ bool AppInit(int argc, char* argv[])
// Parameters
//
// If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
- ParseParameters(argc, argv);
+ gArgs.ParseParameters(argc, argv);
// Process help and version before taking care about datadir
- if (IsArgSet("-?") || IsArgSet("-h") || IsArgSet("-help") || IsArgSet("-version"))
+ if (gArgs.IsArgSet("-?") || gArgs.IsArgSet("-h") || gArgs.IsArgSet("-help") || gArgs.IsArgSet("-version"))
{
std::string strUsage = strprintf(_("%s Daemon"), _(PACKAGE_NAME)) + " " + _("version") + " " + FormatFullVersion() + "\n";
- if (IsArgSet("-version"))
+ if (gArgs.IsArgSet("-version"))
{
strUsage += FormatParagraph(LicenseInfo());
}
@@ -97,14 +96,14 @@ bool AppInit(int argc, char* argv[])
try
{
- if (!boost::filesystem::is_directory(GetDataDir(false)))
+ if (!fs::is_directory(GetDataDir(false)))
{
- fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", GetArg("-datadir", "").c_str());
+ fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
return false;
}
try
{
- ReadConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME));
+ gArgs.ReadConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME));
} catch (const std::exception& e) {
fprintf(stderr,"Error reading configuration file: %s\n", e.what());
return false;
@@ -117,38 +116,35 @@ bool AppInit(int argc, char* argv[])
return false;
}
- // Command-line RPC
- bool fCommandLine = false;
- for (int i = 1; i < argc; i++)
- if (!IsSwitchChar(argv[i][0]) && !boost::algorithm::istarts_with(argv[i], "bitcoin:"))
- fCommandLine = true;
-
- if (fCommandLine)
- {
- fprintf(stderr, "Error: There is no RPC client functionality in bitcoind anymore. Use the bitcoin-cli utility instead.\n");
- exit(EXIT_FAILURE);
+ // Error out when loose non-argument tokens are encountered on command line
+ for (int i = 1; i < argc; i++) {
+ if (!IsSwitchChar(argv[i][0])) {
+ fprintf(stderr, "Error: Command line contains unexpected token '%s', see bitcoind -h for a list of options.\n", argv[i]);
+ exit(EXIT_FAILURE);
+ }
}
+
// -server defaults to true for bitcoind but not for the GUI so do this here
- SoftSetBoolArg("-server", true);
+ gArgs.SoftSetBoolArg("-server", true);
// Set this early so that parameter interactions go to console
InitLogging();
InitParameterInteraction();
if (!AppInitBasicSetup())
{
// InitError will have been called with detailed error, which ends up on console
- exit(1);
+ exit(EXIT_FAILURE);
}
if (!AppInitParameterInteraction())
{
// InitError will have been called with detailed error, which ends up on console
- exit(1);
+ exit(EXIT_FAILURE);
}
if (!AppInitSanityChecks())
{
// InitError will have been called with detailed error, which ends up on console
- exit(1);
+ exit(EXIT_FAILURE);
}
- if (GetBoolArg("-daemon", false))
+ if (gArgs.GetBoolArg("-daemon", false))
{
#if HAVE_DECL_DAEMON
fprintf(stdout, "Bitcoin server starting\n");
@@ -163,21 +159,24 @@ bool AppInit(int argc, char* argv[])
return false;
#endif // HAVE_DECL_DAEMON
}
-
+ // Lock data directory after daemonization
+ if (!AppInitLockDataDirectory())
+ {
+ // If locking the data directory failed, exit immediately
+ exit(EXIT_FAILURE);
+ }
fRet = AppInitMain(threadGroup, scheduler);
}
catch (const std::exception& e) {
PrintExceptionContinue(&e, "AppInit()");
} catch (...) {
- PrintExceptionContinue(NULL, "AppInit()");
+ PrintExceptionContinue(nullptr, "AppInit()");
}
if (!fRet)
{
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
+ threadGroup.join_all();
} else {
WaitForShutdown(&threadGroup);
}
diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp
index 72fe17bdc7..6f27b7b9dc 100644
--- a/src/blockencodings.cpp
+++ b/src/blockencodings.cpp
@@ -15,8 +15,6 @@
#include <unordered_map>
-#define MIN_TRANSACTION_BASE_SIZE (::GetSerializeSize(CTransaction(), SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS))
-
CBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs(const CBlock& block, bool fUseWTXID) :
nonce(GetRand(std::numeric_limits<uint64_t>::max())),
shorttxids(block.vtx.size() - 1), prefilledtxn(1), header(block) {
@@ -47,10 +45,10 @@ uint64_t CBlockHeaderAndShortTxIDs::GetShortID(const uint256& txhash) const {
-ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& cmpctblock) {
+ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector<std::pair<uint256, CTransactionRef>>& extra_txn) {
if (cmpctblock.header.IsNull() || (cmpctblock.shorttxids.empty() && cmpctblock.prefilledtxn.empty()))
return READ_STATUS_INVALID;
- if (cmpctblock.shorttxids.size() + cmpctblock.prefilledtxn.size() > MAX_BLOCK_BASE_SIZE / MIN_TRANSACTION_BASE_SIZE)
+ if (cmpctblock.shorttxids.size() + cmpctblock.prefilledtxn.size() > MAX_BLOCK_WEIGHT / MIN_SERIALIZABLE_TRANSACTION_WEIGHT)
return READ_STATUS_INVALID;
assert(header.IsNull() && txn_available.empty());
@@ -104,6 +102,7 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c
return READ_STATUS_FAILED; // Short ID collision
std::vector<bool> have_txn(txn_available.size());
+ {
LOCK(pool->cs);
const std::vector<std::pair<uint256, CTxMemPool::txiter> >& vTxHashes = pool->vTxHashes;
for (size_t i = 0; i < vTxHashes.size(); i++) {
@@ -130,8 +129,40 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c
if (mempool_count == shorttxids.size())
break;
}
+ }
- LogPrint("cmpctblock", "Initialized PartiallyDownloadedBlock for block %s using a cmpctblock of size %lu\n", cmpctblock.header.GetHash().ToString(), GetSerializeSize(cmpctblock, SER_NETWORK, PROTOCOL_VERSION));
+ for (size_t i = 0; i < extra_txn.size(); i++) {
+ uint64_t shortid = cmpctblock.GetShortID(extra_txn[i].first);
+ std::unordered_map<uint64_t, uint16_t>::iterator idit = shorttxids.find(shortid);
+ if (idit != shorttxids.end()) {
+ if (!have_txn[idit->second]) {
+ txn_available[idit->second] = extra_txn[i].second;
+ have_txn[idit->second] = true;
+ mempool_count++;
+ extra_count++;
+ } else {
+ // If we find two mempool/extra txn that match the short id, just
+ // request it.
+ // This should be rare enough that the extra bandwidth doesn't matter,
+ // but eating a round-trip due to FillBlock failure would be annoying
+ // Note that we don't want duplication between extra_txn and mempool to
+ // trigger this case, so we compare witness hashes first
+ if (txn_available[idit->second] &&
+ txn_available[idit->second]->GetWitnessHash() != extra_txn[i].second->GetWitnessHash()) {
+ txn_available[idit->second].reset();
+ mempool_count--;
+ extra_count--;
+ }
+ }
+ }
+ // Though ideally we'd continue scanning for the two-txn-match-shortid case,
+ // the performance win of an early exit here is too good to pass up and worth
+ // the extra risk.
+ if (mempool_count == shorttxids.size())
+ break;
+ }
+
+ LogPrint(BCLog::CMPCTBLOCK, "Initialized PartiallyDownloadedBlock for block %s using a cmpctblock of size %lu\n", cmpctblock.header.GetHash().ToString(), GetSerializeSize(cmpctblock, SER_NETWORK, PROTOCOL_VERSION));
return READ_STATUS_OK;
}
@@ -139,7 +170,7 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c
bool PartiallyDownloadedBlock::IsTxAvailable(size_t index) const {
assert(!header.IsNull());
assert(index < txn_available.size());
- return txn_available[index] ? true : false;
+ return txn_available[index] != nullptr;
}
ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector<CTransactionRef>& vtx_missing) {
@@ -176,10 +207,11 @@ ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector<
return READ_STATUS_CHECKBLOCK_FAILED;
}
- LogPrint("cmpctblock", "Successfully reconstructed block %s with %lu txn prefilled, %lu txn from mempool and %lu txn requested\n", hash.ToString(), prefilled_count, mempool_count, vtx_missing.size());
+ LogPrint(BCLog::CMPCTBLOCK, "Successfully reconstructed block %s with %lu txn prefilled, %lu txn from mempool (incl at least %lu from extra pool) and %lu txn requested\n", hash.ToString(), prefilled_count, mempool_count, extra_count, vtx_missing.size());
if (vtx_missing.size() < 5) {
- for (const auto& tx : vtx_missing)
- LogPrint("cmpctblock", "Reconstructed block %s required tx %s\n", hash.ToString(), tx->GetHash().ToString());
+ for (const auto& tx : vtx_missing) {
+ LogPrint(BCLog::CMPCTBLOCK, "Reconstructed block %s required tx %s\n", hash.ToString(), tx->GetHash().ToString());
+ }
}
return READ_STATUS_OK;
diff --git a/src/blockencodings.h b/src/blockencodings.h
index 809ccbf936..50478f9f32 100644
--- a/src/blockencodings.h
+++ b/src/blockencodings.h
@@ -16,7 +16,7 @@ struct TransactionCompressor {
private:
CTransactionRef& tx;
public:
- TransactionCompressor(CTransactionRef& txIn) : tx(txIn) {}
+ explicit TransactionCompressor(CTransactionRef& txIn) : tx(txIn) {}
ADD_SERIALIZE_METHODS;
@@ -75,7 +75,7 @@ public:
std::vector<CTransactionRef> txn;
BlockTransactions() {}
- BlockTransactions(const BlockTransactionsRequest& req) :
+ explicit BlockTransactions(const BlockTransactionsRequest& req) :
blockhash(req.blockhash), txn(req.indexes.size()) {}
ADD_SERIALIZE_METHODS;
@@ -99,7 +99,7 @@ public:
}
};
-// Dumb serialization/storage-helper for CBlockHeaderAndShortTxIDs and PartiallyDownlaodedBlock
+// Dumb serialization/storage-helper for CBlockHeaderAndShortTxIDs and PartiallyDownloadedBlock
struct PrefilledTransaction {
// Used as an offset since last prefilled tx in CBlockHeaderAndShortTxIDs,
// as a proper transaction-in-block-index in PartiallyDownloadedBlock
@@ -194,13 +194,14 @@ public:
class PartiallyDownloadedBlock {
protected:
std::vector<CTransactionRef> txn_available;
- size_t prefilled_count = 0, mempool_count = 0;
+ size_t prefilled_count = 0, mempool_count = 0, extra_count = 0;
CTxMemPool* pool;
public:
CBlockHeader header;
- PartiallyDownloadedBlock(CTxMemPool* poolIn) : pool(poolIn) {}
+ explicit PartiallyDownloadedBlock(CTxMemPool* poolIn) : pool(poolIn) {}
- ReadStatus InitData(const CBlockHeaderAndShortTxIDs& cmpctblock);
+ // extra_txn is a list of extra transactions to look at, in <witness hash, reference> form
+ ReadStatus InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector<std::pair<uint256, CTransactionRef>>& extra_txn);
bool IsTxAvailable(size_t index) const;
ReadStatus FillBlock(CBlock& block, const std::vector<CTransactionRef>& vtx_missing);
};
diff --git a/src/bloom.cpp b/src/bloom.cpp
index 520e10cdc8..fa884f0bf3 100644
--- a/src/bloom.cpp
+++ b/src/bloom.cpp
@@ -14,20 +14,17 @@
#include <math.h>
#include <stdlib.h>
-#include <boost/foreach.hpp>
#define LN2SQUARED 0.4804530139182014246671025263266649717305529515945455
#define LN2 0.6931471805599453094172321214581765680755001343602552
-using namespace std;
-
-CBloomFilter::CBloomFilter(unsigned int nElements, double nFPRate, unsigned int nTweakIn, unsigned char nFlagsIn) :
+CBloomFilter::CBloomFilter(const unsigned int nElements, const double nFPRate, const unsigned int nTweakIn, unsigned char nFlagsIn) :
/**
* The ideal size for a bloom filter with a given number of elements and false positive rate is:
* - nElements * log(fp rate) / ln(2)^2
* We ignore filter parameters which will create a bloom filter larger than the protocol limits
*/
- vData(min((unsigned int)(-1 / LN2SQUARED * nElements * log(nFPRate)), MAX_BLOOM_FILTER_SIZE * 8) / 8),
+ vData(std::min((unsigned int)(-1 / LN2SQUARED * nElements * log(nFPRate)), MAX_BLOOM_FILTER_SIZE * 8) / 8),
/**
* The ideal number of hash functions is filter size * ln(2) / number of elements
* Again, we ignore filter parameters which will create a bloom filter with more hash functions than the protocol limits
@@ -35,14 +32,14 @@ CBloomFilter::CBloomFilter(unsigned int nElements, double nFPRate, unsigned int
*/
isFull(false),
isEmpty(true),
- nHashFuncs(min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)),
+ nHashFuncs(std::min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)),
nTweak(nTweakIn),
nFlags(nFlagsIn)
{
}
// Private constructor used by CRollingBloomFilter
-CBloomFilter::CBloomFilter(unsigned int nElements, double nFPRate, unsigned int nTweakIn) :
+CBloomFilter::CBloomFilter(const unsigned int nElements, const double nFPRate, const unsigned int nTweakIn) :
vData((unsigned int)(-1 / LN2SQUARED * nElements * log(nFPRate)) / 8),
isFull(false),
isEmpty(true),
@@ -58,7 +55,7 @@ inline unsigned int CBloomFilter::Hash(unsigned int nHashNum, const std::vector<
return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash) % (vData.size() * 8);
}
-void CBloomFilter::insert(const vector<unsigned char>& vKey)
+void CBloomFilter::insert(const std::vector<unsigned char>& vKey)
{
if (isFull)
return;
@@ -75,17 +72,17 @@ void CBloomFilter::insert(const COutPoint& outpoint)
{
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << outpoint;
- vector<unsigned char> data(stream.begin(), stream.end());
+ std::vector<unsigned char> data(stream.begin(), stream.end());
insert(data);
}
void CBloomFilter::insert(const uint256& hash)
{
- vector<unsigned char> data(hash.begin(), hash.end());
+ std::vector<unsigned char> data(hash.begin(), hash.end());
insert(data);
}
-bool CBloomFilter::contains(const vector<unsigned char>& vKey) const
+bool CBloomFilter::contains(const std::vector<unsigned char>& vKey) const
{
if (isFull)
return true;
@@ -105,13 +102,13 @@ bool CBloomFilter::contains(const COutPoint& outpoint) const
{
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << outpoint;
- vector<unsigned char> data(stream.begin(), stream.end());
+ std::vector<unsigned char> data(stream.begin(), stream.end());
return contains(data);
}
bool CBloomFilter::contains(const uint256& hash) const
{
- vector<unsigned char> data(hash.begin(), hash.end());
+ std::vector<unsigned char> data(hash.begin(), hash.end());
return contains(data);
}
@@ -122,7 +119,7 @@ void CBloomFilter::clear()
isEmpty = true;
}
-void CBloomFilter::reset(unsigned int nNewTweak)
+void CBloomFilter::reset(const unsigned int nNewTweak)
{
clear();
nTweak = nNewTweak;
@@ -154,7 +151,7 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx)
// This means clients don't have to update the filter themselves when a new relevant tx
// is discovered in order to find spending transactions, which avoids round-tripping and race conditions.
CScript::const_iterator pc = txout.scriptPubKey.begin();
- vector<unsigned char> data;
+ std::vector<unsigned char> data;
while (pc < txout.scriptPubKey.end())
{
opcodetype opcode;
@@ -168,7 +165,7 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx)
else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY)
{
txnouttype type;
- vector<vector<unsigned char> > vSolutions;
+ std::vector<std::vector<unsigned char> > vSolutions;
if (Solver(txout.scriptPubKey, type, vSolutions) &&
(type == TX_PUBKEY || type == TX_MULTISIG))
insert(COutPoint(hash, i));
@@ -181,7 +178,7 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx)
if (fFound)
return true;
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ for (const CTxIn& txin : tx.vin)
{
// Match if the filter contains an outpoint tx spends
if (contains(txin.prevout))
@@ -189,7 +186,7 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx)
// Match if the filter contains any arbitrary script data element in any scriptSig in tx
CScript::const_iterator pc = txin.scriptSig.begin();
- vector<unsigned char> data;
+ std::vector<unsigned char> data;
while (pc < txin.scriptSig.end())
{
opcodetype opcode;
@@ -216,7 +213,7 @@ void CBloomFilter::UpdateEmptyFull()
isEmpty = empty;
}
-CRollingBloomFilter::CRollingBloomFilter(unsigned int nElements, double fpRate)
+CRollingBloomFilter::CRollingBloomFilter(const unsigned int nElements, const double fpRate)
{
double logFpRate = log(fpRate);
/* The optimal number of hash functions is log(fpRate) / log(0.5), but
@@ -256,8 +253,8 @@ void CRollingBloomFilter::insert(const std::vector<unsigned char>& vKey)
if (nGeneration == 4) {
nGeneration = 1;
}
- uint64_t nGenerationMask1 = -(uint64_t)(nGeneration & 1);
- uint64_t nGenerationMask2 = -(uint64_t)(nGeneration >> 1);
+ uint64_t nGenerationMask1 = 0 - (uint64_t)(nGeneration & 1);
+ uint64_t nGenerationMask2 = 0 - (uint64_t)(nGeneration >> 1);
/* Wipe old entries that used this generation number. */
for (uint32_t p = 0; p < data.size(); p += 2) {
uint64_t p1 = data[p], p2 = data[p + 1];
@@ -280,7 +277,7 @@ void CRollingBloomFilter::insert(const std::vector<unsigned char>& vKey)
void CRollingBloomFilter::insert(const uint256& hash)
{
- vector<unsigned char> vData(hash.begin(), hash.end());
+ std::vector<unsigned char> vData(hash.begin(), hash.end());
insert(vData);
}
@@ -300,7 +297,7 @@ bool CRollingBloomFilter::contains(const std::vector<unsigned char>& vKey) const
bool CRollingBloomFilter::contains(const uint256& hash) const
{
- vector<unsigned char> vData(hash.begin(), hash.end());
+ std::vector<unsigned char> vData(hash.begin(), hash.end());
return contains(vData);
}
diff --git a/src/bloom.h b/src/bloom.h
index 5ad727c330..7ca9682239 100644
--- a/src/bloom.h
+++ b/src/bloom.h
@@ -54,7 +54,7 @@ private:
unsigned int Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const;
// Private constructor for CRollingBloomFilter, no restrictions on size
- CBloomFilter(unsigned int nElements, double nFPRate, unsigned int nTweak);
+ CBloomFilter(const unsigned int nElements, const double nFPRate, const unsigned int nTweak);
friend class CRollingBloomFilter;
public:
@@ -67,7 +67,7 @@ public:
* It should generally always be a random value (and is largely only exposed for unit testing)
* nFlags should be one of the BLOOM_UPDATE_* enums (not _MASK)
*/
- CBloomFilter(unsigned int nElements, double nFPRate, unsigned int nTweak, unsigned char nFlagsIn);
+ CBloomFilter(const unsigned int nElements, const double nFPRate, const unsigned int nTweak, unsigned char nFlagsIn);
CBloomFilter() : isFull(true), isEmpty(false), nHashFuncs(0), nTweak(0), nFlags(0) {}
ADD_SERIALIZE_METHODS;
@@ -89,7 +89,7 @@ public:
bool contains(const uint256& hash) const;
void clear();
- void reset(unsigned int nNewTweak);
+ void reset(const 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)
@@ -122,7 +122,7 @@ public:
// 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);
+ CRollingBloomFilter(const unsigned int nElements, const double nFPRate);
void insert(const std::vector<unsigned char>& vKey);
void insert(const uint256& hash);
diff --git a/src/chain.cpp b/src/chain.cpp
index 0f4d422b9f..47acde882e 100644
--- a/src/chain.cpp
+++ b/src/chain.cpp
@@ -5,13 +5,11 @@
#include "chain.h"
-using namespace std;
-
/**
* CChain implementation
*/
void CChain::SetTip(CBlockIndex *pindex) {
- if (pindex == NULL) {
+ if (pindex == nullptr) {
vChain.clear();
return;
}
@@ -51,8 +49,8 @@ CBlockLocator CChain::GetLocator(const CBlockIndex *pindex) const {
}
const CBlockIndex *CChain::FindFork(const CBlockIndex *pindex) const {
- if (pindex == NULL) {
- return NULL;
+ if (pindex == nullptr) {
+ return nullptr;
}
if (pindex->nHeight > Height())
pindex = pindex->GetAncestor(Height());
@@ -65,7 +63,7 @@ CBlockIndex* CChain::FindEarliestAtLeast(int64_t nTime) const
{
std::vector<CBlockIndex*>::const_iterator lower = std::lower_bound(vChain.begin(), vChain.end(), nTime,
[](CBlockIndex* pBlock, const int64_t& time) -> bool { return pBlock->GetBlockTimeMax() < time; });
- return (lower == vChain.end() ? NULL : *lower);
+ return (lower == vChain.end() ? nullptr : *lower);
}
/** Turn the lowest '1' bit in the binary representation of a number into a '0'. */
@@ -85,14 +83,14 @@ int static inline GetSkipHeight(int height) {
CBlockIndex* CBlockIndex::GetAncestor(int height)
{
if (height > nHeight || height < 0)
- return NULL;
+ return nullptr;
CBlockIndex* pindexWalk = this;
int heightWalk = nHeight;
while (heightWalk > height) {
int heightSkip = GetSkipHeight(heightWalk);
int heightSkipPrev = GetSkipHeight(heightWalk - 1);
- if (pindexWalk->pskip != NULL &&
+ if (pindexWalk->pskip != nullptr &&
(heightSkip == height ||
(heightSkip > height && !(heightSkipPrev < heightSkip - 2 &&
heightSkipPrev >= height)))) {
@@ -128,7 +126,7 @@ arith_uint256 GetBlockProof(const CBlockIndex& block)
if (fNegative || fOverflow || bnTarget == 0)
return 0;
// We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256
- // as it's too large for a arith_uint256. However, as 2**256 is at least as large
+ // as it's too large for an arith_uint256. However, as 2**256 is at least as large
// as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1,
// or ~bnTarget / (nTarget+1) + 1.
return (~bnTarget / (bnTarget + 1)) + 1;
@@ -150,3 +148,22 @@ int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& fr
}
return sign * r.GetLow64();
}
+
+/** Find the last common ancestor two blocks have.
+ * Both pa and pb must be non-nullptr. */
+const CBlockIndex* LastCommonAncestor(const CBlockIndex* pa, const CBlockIndex* pb) {
+ if (pa->nHeight > pb->nHeight) {
+ pa = pa->GetAncestor(pb->nHeight);
+ } else if (pb->nHeight > pa->nHeight) {
+ pb = pb->GetAncestor(pa->nHeight);
+ }
+
+ while (pa != pb && pa && pb) {
+ pa = pa->pprev;
+ pb = pb->pprev;
+ }
+
+ // Eventually all chain branches meet at the genesis block.
+ assert(pa == pb);
+ return pa;
+}
diff --git a/src/chain.h b/src/chain.h
index acb29b667b..f1036e5d92 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -14,6 +14,20 @@
#include <vector>
+/**
+ * Maximum amount of time that a block timestamp is allowed to exceed the
+ * current network-adjusted time before the block will be accepted.
+ */
+static const int64_t MAX_FUTURE_BLOCK_TIME = 2 * 60 * 60;
+
+/**
+ * Timestamp window used as a grace period by code that compares external
+ * timestamps (such as timestamps passed to RPCs, or wallet key creation times)
+ * to block timestamps. This should be set at least as high as
+ * MAX_FUTURE_BLOCK_TIME.
+ */
+static const int64_t TIMESTAMP_WINDOW = MAX_FUTURE_BLOCK_TIME;
+
class CBlockFileInfo
{
public:
@@ -190,26 +204,26 @@ public:
unsigned int nChainTx;
//! Verification status of this block. See enum BlockStatus
- unsigned int nStatus;
+ uint32_t nStatus;
//! block header
- int nVersion;
+ int32_t nVersion;
uint256 hashMerkleRoot;
- unsigned int nTime;
- unsigned int nBits;
- unsigned int nNonce;
+ uint32_t nTime;
+ uint32_t nBits;
+ uint32_t nNonce;
//! (memory only) Sequential id assigned to distinguish order in which blocks are received.
int32_t nSequenceId;
- //! (memory only) Maximum nTime in the chain upto and including this block.
+ //! (memory only) Maximum nTime in the chain up to and including this block.
unsigned int nTimeMax;
void SetNull()
{
- phashBlock = NULL;
- pprev = NULL;
- pskip = NULL;
+ phashBlock = nullptr;
+ pprev = nullptr;
+ pskip = nullptr;
nHeight = 0;
nFile = 0;
nDataPos = 0;
@@ -233,7 +247,7 @@ public:
SetNull();
}
- CBlockIndex(const CBlockHeader& block)
+ explicit CBlockIndex(const CBlockHeader& block)
{
SetNull();
@@ -348,6 +362,9 @@ public:
arith_uint256 GetBlockProof(const CBlockIndex& block);
/** Return the time it would take to redo the work difference between from and to, assuming the current hashrate corresponds to the difficulty at tip, in seconds. */
int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params&);
+/** Find the forking point between two chain tips. */
+const CBlockIndex* LastCommonAncestor(const CBlockIndex* pa, const CBlockIndex* pb);
+
/** Used to marshal pointers into hashes for db storage. */
class CDiskBlockIndex : public CBlockIndex
@@ -367,9 +384,9 @@ public:
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
- int nVersion = s.GetVersion();
+ int _nVersion = s.GetVersion();
if (!(s.GetType() & SER_GETHASH))
- READWRITE(VARINT(nVersion));
+ READWRITE(VARINT(_nVersion));
READWRITE(VARINT(nHeight));
READWRITE(VARINT(nStatus));
@@ -420,20 +437,20 @@ private:
std::vector<CBlockIndex*> vChain;
public:
- /** Returns the index entry for the genesis block of this chain, or NULL if none. */
+ /** Returns the index entry for the genesis block of this chain, or nullptr if none. */
CBlockIndex *Genesis() const {
- return vChain.size() > 0 ? vChain[0] : NULL;
+ return vChain.size() > 0 ? vChain[0] : nullptr;
}
- /** Returns the index entry for the tip of this chain, or NULL if none. */
+ /** Returns the index entry for the tip of this chain, or nullptr if none. */
CBlockIndex *Tip() const {
- return vChain.size() > 0 ? vChain[vChain.size() - 1] : NULL;
+ return vChain.size() > 0 ? vChain[vChain.size() - 1] : nullptr;
}
- /** Returns the index entry at a particular height in this chain, or NULL if no such height exists. */
+ /** Returns the index entry at a particular height in this chain, or nullptr if no such height exists. */
CBlockIndex *operator[](int nHeight) const {
if (nHeight < 0 || nHeight >= (int)vChain.size())
- return NULL;
+ return nullptr;
return vChain[nHeight];
}
@@ -448,12 +465,12 @@ public:
return (*this)[pindex->nHeight] == pindex;
}
- /** Find the successor of a block in this chain, or NULL if the given index is not found or is the tip. */
+ /** Find the successor of a block in this chain, or nullptr if the given index is not found or is the tip. */
CBlockIndex *Next(const CBlockIndex *pindex) const {
if (Contains(pindex))
return (*this)[pindex->nHeight + 1];
else
- return NULL;
+ return nullptr;
}
/** Return the maximal height in the chain. Is equal to chain.Tip() ? chain.Tip()->nHeight : -1. */
@@ -465,7 +482,7 @@ public:
void SetTip(CBlockIndex *pindex);
/** Return a CBlockLocator that refers to a block in this chain (by default the tip). */
- CBlockLocator GetLocator(const CBlockIndex *pindex = NULL) const;
+ CBlockLocator GetLocator(const CBlockIndex *pindex = nullptr) const;
/** Find the last common block between this chain and a block index entry. */
const CBlockIndex *FindFork(const CBlockIndex *pindex) const;
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index d99f800f0a..85c9cd6934 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -12,8 +12,6 @@
#include <assert.h>
-#include <boost/assign/list_of.hpp>
-
#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)
@@ -55,6 +53,12 @@ static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits
return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTime, nNonce, nBits, nVersion, genesisReward);
}
+void CChainParams::UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout)
+{
+ consensus.vDeployments[d].nStartTime = nStartTime;
+ consensus.vDeployments[d].nTimeout = nTimeout;
+}
+
/**
* Main network
*/
@@ -97,10 +101,10 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1510704000; // November 15th, 2017.
// The best chain should have at least this much work.
- consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000002cb971dd56d1c583c20f90");
+ consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000723d3581fe1bd55373540a");
// By default assume that the signatures in ancestors of this block are valid.
- consensus.defaultAssumeValid = uint256S("0x0000000000000000030abc968e1bd635736e880b946085c93152969b9a81a6e2"); //447235
+ consensus.defaultAssumeValid = uint256S("0x0000000000000000003b9ce759c2a087d52abc4266f8f4ebd6d768b89defa50a"); //477890
/**
* The message start string is designed to be unlikely to occur in normal data.
@@ -120,53 +124,54 @@ public:
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
// Note that of those with the service bits flag, most only support a subset of possible options
- vSeeds.push_back(CDNSSeedData("bitcoin.sipa.be", "seed.bitcoin.sipa.be", true)); // Pieter Wuille, only supports x1, x5, x9, and xd
- vSeeds.push_back(CDNSSeedData("bluematt.me", "dnsseed.bluematt.me", true)); // Matt Corallo, only supports x9
- vSeeds.push_back(CDNSSeedData("dashjr.org", "dnsseed.bitcoin.dashjr.org")); // Luke Dashjr
- vSeeds.push_back(CDNSSeedData("bitcoinstats.com", "seed.bitcoinstats.com", true)); // Christian Decker, supports x1 - xf
- vSeeds.push_back(CDNSSeedData("xf2.org", "bitseed.xf2.org")); // Jeff Garzik
- vSeeds.push_back(CDNSSeedData("bitcoin.jonasschnelli.ch", "seed.bitcoin.jonasschnelli.ch", true)); // Jonas Schnelli, only supports x1, x5, x9, and xd
+ vSeeds.emplace_back("seed.bitcoin.sipa.be", true); // Pieter Wuille, only supports x1, x5, x9, and xd
+ vSeeds.emplace_back("dnsseed.bluematt.me", true); // Matt Corallo, only supports x9
+ vSeeds.emplace_back("dnsseed.bitcoin.dashjr.org", false); // Luke Dashjr
+ vSeeds.emplace_back("seed.bitcoinstats.com", true); // Christian Decker, supports x1 - xf
+ vSeeds.emplace_back("seed.bitcoin.jonasschnelli.ch", true); // Jonas Schnelli, only supports x1, x5, x9, and xd
+ vSeeds.emplace_back("seed.btc.petertodd.org", true); // Peter Todd, only supports x1, x5, x9, and xd
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5);
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,128);
- base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x88)(0xB2)(0x1E).convert_to_container<std::vector<unsigned char> >();
- base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x88)(0xAD)(0xE4).convert_to_container<std::vector<unsigned char> >();
+ base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x88, 0xB2, 0x1E};
+ base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x88, 0xAD, 0xE4};
+
+ bech32_hrp = "bc";
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main));
- fMiningRequiresPeers = true;
fDefaultConsistencyChecks = false;
fRequireStandard = true;
fMineBlocksOnDemand = false;
checkpointData = (CCheckpointData) {
- boost::assign::map_list_of
- ( 11111, uint256S("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"))
- ( 33333, uint256S("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6"))
- ( 74000, uint256S("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20"))
- (105000, uint256S("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97"))
- (134444, uint256S("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"))
- (168000, uint256S("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763"))
- (193000, uint256S("0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317"))
- (210000, uint256S("0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e"))
- (216116, uint256S("0x00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e"))
- (225430, uint256S("0x00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932"))
- (250000, uint256S("0x000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214"))
- (279000, uint256S("0x0000000000000001ae8c72a0b0c301f67e3afca10e819efa9041e458e9bd7e40"))
- (295000, uint256S("0x00000000000000004d9b4ef50f0f9d686fd69db2e03af35a100370c64632a983"))
+ {
+ { 11111, uint256S("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")},
+ { 33333, uint256S("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6")},
+ { 74000, uint256S("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20")},
+ {105000, uint256S("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97")},
+ {134444, uint256S("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe")},
+ {168000, uint256S("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763")},
+ {193000, uint256S("0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317")},
+ {210000, uint256S("0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e")},
+ {216116, uint256S("0x00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e")},
+ {225430, uint256S("0x00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932")},
+ {250000, uint256S("0x000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214")},
+ {279000, uint256S("0x0000000000000001ae8c72a0b0c301f67e3afca10e819efa9041e458e9bd7e40")},
+ {295000, uint256S("0x00000000000000004d9b4ef50f0f9d686fd69db2e03af35a100370c64632a983")},
+ }
};
chainTxData = ChainTxData{
- // Data as of block 00000000000000000166d612d5595e2b1cd88d71d695fc580af64d8da8658c23 (height 446482).
- 1483472411, // * UNIX timestamp of last known number of transactions
- 184495391, // * total number of transactions between genesis and that timestamp
+ // Data as of block 000000000000000000d97e53664d17967bd4ee50b23abb92e54a34eb222d15ae (height 478913).
+ 1501801925, // * UNIX timestamp of last known number of transactions
+ 243756039, // * total number of transactions between genesis and that timestamp
// (the tx=... number in the SetBestChain debug.log lines)
- 3.2 // * estimated number of transactions per second after that timestamp
+ 3.1 // * estimated number of transactions per second after that timestamp
};
}
};
-static CMainParams mainParams;
/**
* Testnet (v3)
@@ -202,10 +207,10 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1493596800; // May 1st 2017
// The best chain should have at least this much work.
- consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000000000198b4def2baa9338d6");
+ consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000002830dab7f76dbb7d63");
// By default assume that the signatures in ancestors of this block are valid.
- consensus.defaultAssumeValid = uint256S("0x000000000871ee6842d3648317ccc8a435eb8cc3c2429aee94faff9ba26b05a0"); //1043841
+ consensus.defaultAssumeValid = uint256S("0x0000000002e9e7b00e1f6dc5123a04aad68dd0f0968d8c7aa45f6640795c37b1"); //1135275
pchMessageStart[0] = 0x0b;
pchMessageStart[1] = 0x11;
@@ -222,40 +227,41 @@ public:
vFixedSeeds.clear();
vSeeds.clear();
// nodes with support for servicebits filtering should be at the top
- vSeeds.push_back(CDNSSeedData("testnetbitcoin.jonasschnelli.ch", "testnet-seed.bitcoin.jonasschnelli.ch", true));
- vSeeds.push_back(CDNSSeedData("petertodd.org", "seed.tbtc.petertodd.org", true));
- vSeeds.push_back(CDNSSeedData("bluematt.me", "testnet-seed.bluematt.me"));
- vSeeds.push_back(CDNSSeedData("bitcoin.schildbach.de", "testnet-seed.bitcoin.schildbach.de"));
+ vSeeds.emplace_back("testnet-seed.bitcoin.jonasschnelli.ch", true);
+ vSeeds.emplace_back("seed.tbtc.petertodd.org", true);
+ vSeeds.emplace_back("testnet-seed.bluematt.me", false);
+ vSeeds.emplace_back("testnet-seed.bitcoin.schildbach.de", false);
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> >();
+ base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
+ base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
+
+ bech32_hrp = "tb";
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test));
- fMiningRequiresPeers = true;
fDefaultConsistencyChecks = false;
fRequireStandard = false;
fMineBlocksOnDemand = false;
checkpointData = (CCheckpointData) {
- boost::assign::map_list_of
- ( 546, uint256S("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70")),
+ {
+ {546, uint256S("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70")},
+ }
};
chainTxData = ChainTxData{
- // Data as of block 00000000c2872f8f8a8935c8e3c5862be9038c97d4de2cf37ed496991166928a (height 1063660)
- 1483546230,
- 12834668,
+ // Data as of block 00000000000001c200b9790dc637d3bb141fe77d155b966ed775b17e109f7c6c (height 1156179)
+ 1501802953,
+ 14706531,
0.15
};
}
};
-static CTestNetParams testNetParams;
/**
* Regression test
@@ -307,14 +313,14 @@ public:
vFixedSeeds.clear(); //!< Regtest mode doesn't have any fixed seeds.
vSeeds.clear(); //!< Regtest mode doesn't have any DNS seeds.
- fMiningRequiresPeers = false;
fDefaultConsistencyChecks = true;
fRequireStandard = false;
fMineBlocksOnDemand = true;
- checkpointData = (CCheckpointData){
- boost::assign::map_list_of
- ( 0, uint256S("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"))
+ checkpointData = (CCheckpointData) {
+ {
+ {0, uint256S("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")},
+ }
};
chainTxData = ChainTxData{
@@ -326,45 +332,38 @@ public:
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> >();
- }
+ base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
+ base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
- void UpdateBIP9Parameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout)
- {
- consensus.vDeployments[d].nStartTime = nStartTime;
- consensus.vDeployments[d].nTimeout = nTimeout;
+ bech32_hrp = "bcrt";
}
};
-static CRegTestParams regTestParams;
-static CChainParams *pCurrentParams = 0;
+static std::unique_ptr<CChainParams> globalChainParams;
const CChainParams &Params() {
- assert(pCurrentParams);
- return *pCurrentParams;
+ assert(globalChainParams);
+ return *globalChainParams;
}
-CChainParams& Params(const std::string& chain)
+std::unique_ptr<CChainParams> CreateChainParams(const std::string& chain)
{
if (chain == CBaseChainParams::MAIN)
- return mainParams;
+ return std::unique_ptr<CChainParams>(new CMainParams());
else if (chain == CBaseChainParams::TESTNET)
- return testNetParams;
+ return std::unique_ptr<CChainParams>(new CTestNetParams());
else if (chain == CBaseChainParams::REGTEST)
- return regTestParams;
- else
- throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
+ return std::unique_ptr<CChainParams>(new CRegTestParams());
+ throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
}
void SelectParams(const std::string& network)
{
SelectBaseParams(network);
- pCurrentParams = &Params(network);
+ globalChainParams = CreateChainParams(network);
}
-void UpdateRegtestBIP9Parameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout)
+void UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout)
{
- regTestParams.UpdateBIP9Parameters(d, nStartTime, nTimeout);
+ globalChainParams->UpdateVersionBitsParameters(d, nStartTime, nTimeout);
}
-
diff --git a/src/chainparams.h b/src/chainparams.h
index db524e8f8e..3948c9163f 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -11,12 +11,13 @@
#include "primitives/block.h"
#include "protocol.h"
+#include <memory>
#include <vector>
struct CDNSSeedData {
- std::string name, host;
+ std::string host;
bool supportsServiceBitsFiltering;
- CDNSSeedData(const std::string &strName, const std::string &strHost, bool supportsServiceBitsFilteringIn = false) : name(strName), host(strHost), supportsServiceBitsFiltering(supportsServiceBitsFilteringIn) {}
+ CDNSSeedData(const std::string &strHost, bool supportsServiceBitsFilteringIn) : host(strHost), supportsServiceBitsFiltering(supportsServiceBitsFilteringIn) {}
};
struct SeedSpec6 {
@@ -61,8 +62,6 @@ public:
int GetDefaultPort() const { return nDefaultPort; }
const CBlock& GenesisBlock() const { return genesis; }
- /** Make miner wait to have peers to avoid wasting work */
- bool MiningRequiresPeers() const { return fMiningRequiresPeers; }
/** Default value for -checkmempool and -checkblockindex argument */
bool DefaultConsistencyChecks() const { return fDefaultConsistencyChecks; }
/** Policy: Filter transactions that do not match well-defined patterns */
@@ -74,9 +73,11 @@ public:
std::string NetworkIDString() const { return strNetworkID; }
const std::vector<CDNSSeedData>& DNSSeeds() const { return vSeeds; }
const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; }
+ const std::string& Bech32HRP() const { return bech32_hrp; }
const std::vector<SeedSpec6>& FixedSeeds() const { return vFixedSeeds; }
const CCheckpointData& Checkpoints() const { return checkpointData; }
const ChainTxData& TxData() const { return chainTxData; }
+ void UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout);
protected:
CChainParams() {}
@@ -86,10 +87,10 @@ protected:
uint64_t nPruneAfterHeight;
std::vector<CDNSSeedData> vSeeds;
std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES];
+ std::string bech32_hrp;
std::string strNetworkID;
CBlock genesis;
std::vector<SeedSpec6> vFixedSeeds;
- bool fMiningRequiresPeers;
bool fDefaultConsistencyChecks;
bool fRequireStandard;
bool fMineBlocksOnDemand;
@@ -98,15 +99,17 @@ protected:
};
/**
- * Return the currently selected parameters. This won't change after app
- * startup, except for unit tests.
+ * Creates and returns a std::unique_ptr<CChainParams> of the chosen chain.
+ * @returns a CChainParams* of the chosen chain.
+ * @throws a std::runtime_error if the chain is not supported.
*/
-const CChainParams &Params();
+std::unique_ptr<CChainParams> CreateChainParams(const std::string& chain);
/**
- * @returns CChainParams for the given BIP70 chain name.
+ * Return the currently selected parameters. This won't change after app
+ * startup, except for unit tests.
*/
-CChainParams& Params(const std::string& chain);
+const CChainParams &Params();
/**
* Sets the params returned by Params() to those for the given BIP70 chain name.
@@ -115,8 +118,8 @@ CChainParams& Params(const std::string& chain);
void SelectParams(const std::string& chain);
/**
- * Allows modifying the BIP9 regtest parameters.
+ * Allows modifying the Version Bits regtest parameters.
*/
-void UpdateRegtestBIP9Parameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout);
+void UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout);
#endif // BITCOIN_CHAINPARAMS_H
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index cb71a8b550..c966683b72 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -35,7 +35,6 @@ public:
nRPCPort = 8332;
}
};
-static CBaseMainParams mainParams;
/**
* Testnet (v3)
@@ -49,7 +48,6 @@ public:
strDataDir = "testnet3";
}
};
-static CBaseTestNetParams testNetParams;
/*
* Regression test
@@ -59,41 +57,40 @@ class CBaseRegTestParams : public CBaseChainParams
public:
CBaseRegTestParams()
{
- nRPCPort = 18332;
+ nRPCPort = 18443;
strDataDir = "regtest";
}
};
-static CBaseRegTestParams regTestParams;
-static CBaseChainParams* pCurrentBaseParams = 0;
+static std::unique_ptr<CBaseChainParams> globalChainBaseParams;
const CBaseChainParams& BaseParams()
{
- assert(pCurrentBaseParams);
- return *pCurrentBaseParams;
+ assert(globalChainBaseParams);
+ return *globalChainBaseParams;
}
-CBaseChainParams& BaseParams(const std::string& chain)
+std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const std::string& chain)
{
if (chain == CBaseChainParams::MAIN)
- return mainParams;
+ return std::unique_ptr<CBaseChainParams>(new CBaseMainParams());
else if (chain == CBaseChainParams::TESTNET)
- return testNetParams;
+ return std::unique_ptr<CBaseChainParams>(new CBaseTestNetParams());
else if (chain == CBaseChainParams::REGTEST)
- return regTestParams;
+ return std::unique_ptr<CBaseChainParams>(new CBaseRegTestParams());
else
throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
}
void SelectBaseParams(const std::string& chain)
{
- pCurrentBaseParams = &BaseParams(chain);
+ globalChainBaseParams = CreateBaseChainParams(chain);
}
std::string ChainNameFromCommandLine()
{
- bool fRegTest = GetBoolArg("-regtest", false);
- bool fTestNet = GetBoolArg("-testnet", false);
+ bool fRegTest = gArgs.GetBoolArg("-regtest", false);
+ bool fTestNet = gArgs.GetBoolArg("-testnet", false);
if (fTestNet && fRegTest)
throw std::runtime_error("Invalid combination of -regtest and -testnet.");
@@ -103,8 +100,3 @@ std::string ChainNameFromCommandLine()
return CBaseChainParams::TESTNET;
return CBaseChainParams::MAIN;
}
-
-bool AreBaseParamsConfigured()
-{
- return pCurrentBaseParams != NULL;
-}
diff --git a/src/chainparamsbase.h b/src/chainparamsbase.h
index 59493afb9b..fc101f5b77 100644
--- a/src/chainparamsbase.h
+++ b/src/chainparamsbase.h
@@ -5,6 +5,7 @@
#ifndef BITCOIN_CHAINPARAMSBASE_H
#define BITCOIN_CHAINPARAMSBASE_H
+#include <memory>
#include <string>
#include <vector>
@@ -31,6 +32,13 @@ protected:
};
/**
+ * Creates and returns a std::unique_ptr<CBaseChainParams> of the chosen chain.
+ * @returns a CBaseChainParams* of the chosen chain.
+ * @throws a std::runtime_error if the chain is not supported.
+ */
+std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const std::string& chain);
+
+/**
* Append the help messages for the chainparams options to the
* parameter string.
*/
@@ -42,8 +50,6 @@ void AppendParamsHelpMessages(std::string& strUsage, bool debugHelp=true);
*/
const CBaseChainParams& BaseParams();
-CBaseChainParams& BaseParams(const std::string& chain);
-
/** Sets the params returned by Params() to those for the given network. */
void SelectBaseParams(const std::string& chain);
@@ -53,10 +59,4 @@ void SelectBaseParams(const std::string& chain);
*/
std::string ChainNameFromCommandLine();
-/**
- * Return true if SelectBaseParamsFromCommandLine() has been called to select
- * a network.
- */
-bool AreBaseParamsConfigured();
-
#endif // BITCOIN_CHAINPARAMSBASE_H
diff --git a/src/chainparamsseeds.h b/src/chainparamsseeds.h
index 1406e86805..2c99ca8ab0 100644
--- a/src/chainparamsseeds.h
+++ b/src/chainparamsseeds.h
@@ -8,943 +8,1456 @@
* 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,0x05,0x02,0x91,0xc9}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x16,0x8e,0xd6}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x35,0xac,0xc5}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xbd,0xa1,0xa4}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xe6,0x8c,0xa6}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xe7,0x03,0x82}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xff,0x50,0x67}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x0e,0xca,0xe6,0x31}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x12,0x55,0x0b,0x82}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0x5b,0x61,0x19}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0x5e,0x64,0x7a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0x5f,0x63,0x84}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x73,0x08,0xce}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x7f,0x80,0xbf}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x9a,0xb2,0x19}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0xcf,0x67,0x2b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0xcf,0x68,0x69}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0xd2,0xe6,0x96}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0xe0,0x12,0x54}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0xf6,0xa8,0x6a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1b,0xfe,0x40,0x2f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0x06,0x47,0x7b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0x06,0x47,0x7c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0x0e,0x86,0x0d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0x1e,0x24,0xdc}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0xa4,0x06,0x68}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0xaa,0x6a,0xcb}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0xb9,0x86,0xc9}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0xcc,0x80,0x63}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0xcc,0x80,0xdb}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x01,0xdb,0x58}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x61,0x84,0x6d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x78,0xa0,0x37}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x78,0xa9,0x7b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x8b,0x20,0x2e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0xdd,0xa3,0xda}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x26,0x82,0xc0,0x48}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x29,0x4b,0x60,0x50}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x03,0x00,0x31}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x21,0x48,0xb9}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x21,0x60,0x81}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x38,0x04,0x3f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x4f,0x00,0x7f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x4f,0x50,0x66}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x4f,0x61,0x1e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x4f,0x84,0xdb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x02,0xe4,0x46,0xc6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x04,0x0f,0xb4,0x1d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x04,0x0f,0xb4,0x1e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x02,0x43,0x6e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x27,0xe0,0x67}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x2b,0x7c,0x9a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xbd,0xa5,0x66}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xe2,0x95,0x91}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xe4,0x07,0x92}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xe4,0x40,0x47}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xf9,0x98,0x65}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xfe,0x7c,0x37}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xff,0x40,0xe7}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xff,0x5a,0xea}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x0e,0xc0,0x08,0x1b}, 21301},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x12,0x3e,0x03,0x56}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x12,0x55,0x23,0x50}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0x1c,0x80,0x41}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0x6c,0x53,0x0c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0xe9,0x02,0xee}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x1b,0x41,0xa8}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x38,0xf1,0xdb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x40,0x4b,0x84}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x49,0x46,0x1a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x79,0x9a,0x8c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0xcb,0x60,0x48}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0xe1,0x22,0x3e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0xe3,0x45,0x92}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0xe8,0x88,0x77}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0x10,0x7b,0xeb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0x13,0xcd,0x35}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0x84,0x88,0x23}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0xb8,0xea,0x55}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0xd3,0x66,0xa1}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x30,0x40,0x8c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x61,0x8d,0x74}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x78,0xa0,0x0c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x78,0xa4,0x10}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x86,0xe2,0xb5}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x93,0x6e,0x2b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0xc2,0x0a,0x1e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0xf7,0x16,0x35}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x26,0x1b,0x41,0x9e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x26,0x85,0x8d,0x22}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2b,0xf8,0xa0,0x97}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x20,0x82,0x13}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x20,0xc1,0x9d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x2e,0xa1,0x79}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x38,0x61,0x3f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x74,0xb2,0x4f}, 8188},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x10,0xf0,0x62}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x14,0xf6,0x64}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x15,0x61,0x87}, 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,0x2e,0x1c,0xce,0xbc}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x1d,0x14,0xd1}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x32,0xea,0xb3}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x65,0xa0,0xa8}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xa6,0xa1,0x23}, 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,0xda,0xe3,0x5c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xe2,0x6d,0x14}, 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,0xe3,0x42,0x8a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xe5,0xa5,0x9a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xe5,0xa5,0x9b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x3b,0x0a,0xed}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x3b,0x0d,0x3b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x94,0x10,0xd2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xa6,0xa0,0x60}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xbc,0x2c,0x14}, 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,0xea,0x68,0x30}, 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,0xf4,0x00,0x8a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xfe,0x48,0xc3}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x05,0x0d,0x2c}, 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,0x1e,0x25,0x67}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x27,0x69,0x3c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x6a,0x28,0xe7}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x34,0x1d,0x00,0x25}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x34,0x4c,0xc0,0xf6}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x36,0x98,0xc0,0xb3}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x36,0xa9,0x40,0xae}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x36,0xaf,0xa0,0x16}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x36,0xc7,0x80,0x00}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3a,0x60,0xab,0x81}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3a,0xa1,0xee,0x39}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3c,0xfb,0xc3,0xdd}, 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,0x2e,0xe7,0x10,0x95}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2f,0x58,0x23,0xb5}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2f,0x58,0x64,0x82}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2f,0xb8,0x81,0x5e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2f,0xc7,0x44,0xcc}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x1e,0x26,0xcb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x3f,0xa2,0xf2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x61,0x85,0xd0}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x72,0xe3,0xe0}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x33,0x0f,0x00,0x11}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x33,0xae,0x45,0xef}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x34,0x07,0x87,0x45}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x34,0x0e,0x40,0x52}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x34,0xcc,0x69,0x19}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x36,0xff,0xa0,0x57}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3d,0x2f,0x02,0x14}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3d,0x7d,0x83,0x37}, 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,0x41,0x27,0x0c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0x6a,0x10,0x6f}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0x6b,0xc8,0x1e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0x6d,0x14,0x63}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0x85,0xc2,0x02}, 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,0xb7,0x16,0x32}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0xd2,0x55,0x78}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0xd2,0xa2,0x59}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0xee,0x22,0x7d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x40,0x19,0xab,0x49}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x40,0x1b,0xa6,0x1e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x40,0x35,0x89,0x65}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x40,0x47,0x48,0x2c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x40,0x53,0xe1,0x92}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x40,0x79,0x03,0xa3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0x85,0xc2,0x9c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0xb0,0x06,0x5e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0xb6,0xa9,0xde}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0xcd,0x84,0xf5}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0xd8,0xee,0x85}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3f,0xe7,0xef,0xd4}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x40,0x22,0xe7,0x8c}, 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,0x41,0x5e,0x83,0x3b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x41,0xbc,0x88,0xe9}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0x0b,0xa2,0xda}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0x17,0xe4,0x85}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0x5a,0x89,0x59}, 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,0x96,0x69,0x4d}, 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,0x40,0xe9,0xf5,0x27}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x41,0xb7,0x4c,0x49}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0x60,0xc7,0xa6}, 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,0xc2,0x26,0xfe}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0xe7,0x61,0xac}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0xf0,0xed,0x9b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x43,0x9f,0x0d,0x22}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x43,0xcd,0x4a,0xce}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0xc4,0x0c,0x3f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x43,0xd7,0x06,0x22}, 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,0xe3,0x48,0x11}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0x41,0x78,0x35}, 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,0x90,0x04,0x22}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x27,0x31,0xc7}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x32,0xab,0xcd}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x41,0x29,0x15}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x71,0x62,0x3d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x77,0x61,0x27}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x92,0x46,0x7c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0xc1,0x47,0x02}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x46,0x2e,0x0a,0xed}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x46,0x50,0xc8,0xbb}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x46,0xb9,0x61,0x75}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x47,0xfe,0xa0,0x19}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x48,0x1c,0xcb,0x05}, 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,0x53,0xc2,0x7a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x48,0x80,0x20,0xa7}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x48,0xb3,0x88,0x50}, 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,0x4a,0x32,0x2c,0xc1}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0x48,0x3c,0x53}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0x50,0xea,0x74}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0xcf,0xe9,0xc1}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4b,0x70,0xe9,0x80}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4b,0x76,0xa6,0xc5}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4b,0x8c,0x00,0xf1}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4b,0x9f,0xf0,0x42}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4b,0xae,0x05,0x1a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4c,0x48,0xa0,0xfc}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4c,0x48,0xa0,0xfe}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4c,0x4a,0xaa,0x70}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4c,0x4f,0xc9,0x36}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4c,0xaf,0xa6,0xa4}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4c,0xb3,0x69,0x1b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x44,0x25,0xc8}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0xea,0x31,0xc4}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0xf7,0xe5,0x5d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x18,0x48,0x4e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x2f,0x20,0x93}, 8333},
- {{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,0x4e,0x79,0x45,0x17}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x81,0xa7,0x05}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0xc1,0x60,0x9b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4f,0x13,0x25,0xb3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0x42,0xc1,0xc0}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0x45,0xeb,0xe6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0x6f,0x0a,0xdb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0x77,0x8a,0xaf}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0x84,0xc1,0xde}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0xc2,0x2a,0x4c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0xeb,0x29,0xcc}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x0b,0x61,0x2b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x29,0x03,0xd4}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x29,0xab,0x23}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x29,0xab,0x24}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x37,0x40,0xd8}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x54,0x2a,0x38}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x46,0x30,0x30,0xfa}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x46,0x70,0x20,0x1d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x46,0xfa,0x4a,0x14}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x47,0x5d,0xa1,0xa2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x47,0xc6,0x00,0x7e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x48,0x05,0xa7,0x29}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x48,0xe0,0x0b,0x67}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x49,0x48,0xa0,0xd5}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0x7a,0xed,0x7c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4b,0x56,0x89,0x22}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4b,0xa5,0x63,0x90}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4c,0x40,0x4a,0xc1}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4c,0x4c,0xe3,0x88}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4c,0xad,0xa1,0x2c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4c,0xb2,0x16,0x2c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x2f,0x89,0x1b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x4d,0x2e,0xfa}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x5b,0xc1,0x98}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x5f,0xe2,0xc2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x78,0xf6,0xfe}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0xa3,0x88,0x88}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0xcb,0x0d,0x39}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0xec,0x25,0xd6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0xef,0x25,0x0c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0xf7,0xb3,0x2c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x22,0x0e,0x34}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x6d,0xa3,0x99}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0xc4,0xac,0x2d}, 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,0x85,0x2b,0x3f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4f,0x86,0xc9,0x42}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4f,0xa9,0x23,0xeb}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0x39,0xe3,0x0e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0x40,0x41,0x57}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0x56,0x5c,0x46}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4f,0xa0,0x02,0x69}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0x52,0x4d,0x8a}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0x64,0xcb,0x97}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0x65,0x20,0x79}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0xa1,0xb2,0x49}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0xf0,0x81,0xaa}, 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,0x0b,0x37}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x11,0x11,0x28}, 9333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x1e,0x27,0x53}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x5a,0x24,0x07}, 9444},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x88,0xe0,0x4d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0xa2,0xe7,0xd3}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0xb8,0x00,0x8f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0xc6,0x80,0x56}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x0b,0x21,0xe5}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x4f,0x80,0x86}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x76,0xe9,0x6f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x87,0x8b,0x1e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0x93,0x44,0xed}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0xed,0xf0,0x66}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x02,0xf6,0x7f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x07,0x07,0x56}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x07,0x0a,0xee}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x1b,0x60,0x25}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x53,0x60,0x05}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0xe4,0xc2,0xbb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x2d,0x45,0xd8}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x45,0x2c,0xb7}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x48,0xc6,0x44}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x5f,0xcc,0x0a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x76,0xec,0x7f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x76,0xf2,0x04}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x86,0x42,0x92}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xc1,0x6d,0xc7}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xc5,0xd2,0x41}, 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,0xdd,0x6a,0x11}, 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,0xc8,0xcd,0x1e}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xdd,0x6c,0x1b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x89,0x29,0x03}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x8e,0xc5,0xa8}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x8f,0x82,0x13}, 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,0xb7,0x11,0xbf}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xe3,0xad,0x53}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xe6,0x05,0x0f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xe9,0x69,0x97}, 443},
- {{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,0xfa,0x85,0x9e}, 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,0x18,0x45,0x3b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xdd,0x80,0x51}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xdd,0x8b,0x61}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xe8,0xca,0xf6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x3c,0x40,0xfc}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x3d,0x08,0xe4}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x80,0x29,0x30}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x80,0x6f,0x45}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x89,0x29,0x0a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x96,0x2b,0x11}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xa9,0x02,0x2b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xae,0xd1,0x57}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xff,0x2b,0xa3}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x2a,0xc1,0x06}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x2d,0x62,0x57}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x36,0x80,0x0b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xd4,0xc8,0x18}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xd7,0xc6,0x6d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xe6,0x04,0xb1}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0x5f,0xe4,0x53}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0x5f,0xe4,0x7b}, 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,0xd6,0x42,0xa8}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xd6,0x93,0xa2}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xf3,0xa8,0x04}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x56,0x01,0x00,0x12}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0x4f,0x4d,0x6a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0x5b,0x9c,0x6e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0xec,0xc4,0xde}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x55,0x4b,0x98}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x57,0x01,0xe6}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x57,0x5c,0x66}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x59,0x45,0xca}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x61,0x48,0xe5}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0xa4,0x75,0x63}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0xc6,0x20,0x83}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0xca,0xe6,0x57}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0xd6,0xc1,0x9a}, 8343},
- {{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,0x0a,0x9b,0x58}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x2e,0x65,0x2c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xa3,0xe0,0xd4}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xae,0xf8,0x14}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xca,0xe7,0xc6}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xd4,0x4b,0x06}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x34,0x91,0xe7}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x34,0xea,0x46}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x55,0x66,0x71}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x5c,0x5c,0xf7}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x92,0x23,0x7b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xd4,0xc6,0xde}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xd9,0xa3,0x87}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xf5,0x1b,0xb9}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xfb,0xcb,0x05}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0x15,0x90,0xe2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0x19,0xc2,0x0c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0x19,0xc2,0x1c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0x90,0x77,0xde}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xb7,0x8c,0x3e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xd6,0xe4,0xcb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xd6,0xea,0xfe}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xda,0x96,0x01}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xe4,0xc4,0x0a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x56,0x0f,0x02,0xeb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x56,0x3d,0x06,0xd2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0x5c,0x73,0xc2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0x78,0x08,0x05}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0x78,0x25,0xe6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0xe9,0xb5,0x92}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0xef,0x65,0x66}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x57,0x4e,0x7e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x62,0xc6,0x82}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x62,0xe1,0xd6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x63,0x3a,0xc2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x96,0xc0,0x11}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0xc4,0x88,0x1f}, 17556},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0xd0,0x3a,0xc1}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0xd0,0x3a,0xc2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x16,0x60,0x84}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x16,0x68,0x30}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x19,0x50,0x62}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x22,0x63,0x29}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x8e,0xc3,0x70}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xa3,0xe0,0xbb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xa3,0xe0,0xc3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xee,0x4f,0xeb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5a,0x2e,0xf0,0xd6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5a,0x41,0xe8,0x81}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5a,0x47,0x75,0x5a}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5a,0x95,0x26,0xac}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5a,0xa9,0x6a,0x8b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0x40,0x65,0x96}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0x41,0xc4,0xb3}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0x79,0x50,0x11}, 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,0x91,0x4c,0x9c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0x98,0x96,0x23}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xc0,0x89,0x11}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xc4,0xaa,0x6e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5a,0x9c,0x61,0x91}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5a,0xb1,0x30,0x68}, 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,0x87,0x00,0xbb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0x96,0xbd,0x9b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xb9,0xc6,0xd8}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xc4,0x0b,0x2d}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xc5,0x2c,0x85}, 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,0xd2,0x69,0x1c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xd3,0x66,0x65}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xd3,0x6a,0x22}, 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,0xdc,0x2b,0x92}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xde,0x47,0x59}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xe0,0x8c,0xf2}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xe5,0x4c,0x0e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xe0,0x00,0xe3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xe2,0x0a,0x5a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xe4,0x2d,0x82}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xe5,0x4d,0xef}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xee,0x64,0xf9}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xf0,0x8d,0xa9}, 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,0x33,0xa7,0x58}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5c,0xf7,0xe5,0xa3}, 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,0x71,0x24,0xac}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5c,0x36,0x10,0x87}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x59,0x54,0x5d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x64,0x33,0x30}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x64,0x4c,0x97}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x68,0xd6,0xeb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x73,0x56,0xf6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x7b,0x50,0x2f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0xae,0x58,0xd3}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0xbc,0xe0,0xfd}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0x4b,0xef,0x45}, 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,0xd6,0x02,0x4a}, 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,0xec,0xc6,0xfd}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0xf2,0xe5,0x9e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x54,0x8a,0x63}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x5f,0xa8,0x57}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x6e,0xea,0x5d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x82,0x09,0xc8}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0xa5,0xa8,0xa8}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0xaa,0xeb,0xfe}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0xd3,0x82,0x9a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x60,0x2e,0x44,0x68}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x60,0x7f,0xca,0x94}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x61,0x4c,0xab,0x23}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x62,0xa0,0xa0,0x43}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x63,0x7e,0xc5,0xbb}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x63,0xc6,0xad,0x01}, 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,0xa4,0xc9,0xd0}, 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,0x68,0x80,0xe1,0xdf}, 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,0x83,0xc0,0x5e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0x9b,0x2d,0xc9}, 8334},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xc2,0x1c,0xc3}, 8663},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xd3,0x01,0x1b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xdd,0x26,0xb1}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xec,0x09,0x4f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xec,0x81,0xb2}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xec,0xba,0xf9}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xec,0xc2,0x0f}, 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,0x6a,0xb9,0x26,0x43}, 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,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,0xaa,0x0d,0xb8}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0xb5,0xfa,0xd8}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0xbf,0x65,0x6f}, 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,0x5d,0xbe,0x45,0xf2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0x4a,0x51,0x5d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0x9c,0x23,0x08}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0xb0,0xed,0xf1}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0xb5,0x2c,0x68}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0xe3,0x2b,0xab}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x4f,0x66,0xd0}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x4f,0x66,0xd1}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x9a,0xed,0x18}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0xb7,0x30,0x3e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0xb7,0x30,0x47}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0xd5,0xa1,0x02}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0xd5,0xc9,0x5e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x60,0x14,0xe3,0x27}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x60,0x1c,0x29,0x5b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x62,0x7f,0x82,0x11}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x64,0x24,0x30,0x65}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x65,0x00,0x51,0x2a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x65,0x00,0x51,0x2b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x0b,0x40,0x2e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x18,0xf4,0x45}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x2f,0xd2,0x32}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x4c,0x29,0xa9}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x50,0xa8,0x39}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0xcb,0x33,0xba}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0xe0,0x76,0x4f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0xfa,0x04,0x4a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xc0,0xaa,0xca}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xc4,0x00,0x63}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xc7,0xc0,0x55}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xdb,0xfb,0x2e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xdf,0x6c,0x21}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xed,0x02,0xbd}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xf7,0xe6,0x1c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0x96,0x2d,0xd2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0xae,0x22,0x4d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0xae,0x22,0x4e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0xb4,0x47,0x2f}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6c,0x3b,0x0c,0xa3}, 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,0x6d,0xc1,0xa0,0x8c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xc5,0x0d,0x36}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xe6,0x07,0xf8}, 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,0xec,0x89,0x50}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xfb,0xa1,0x79}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x70,0x41,0xe7,0xe2}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x73,0x46,0xa6,0x39}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x73,0x9f,0x2a,0x50}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x75,0x12,0x49,0x22}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6c,0xa8,0x25,0x0d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6c,0xaf,0x03,0x12}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6c,0xea,0xc1,0x6a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0x09,0xad,0x0d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0x65,0xdc,0x97}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xac,0x68,0x77}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xc3,0xc1,0x8a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xce,0xb1,0x15}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xe2,0x23,0x1c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xff,0x00,0x6b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x71,0x1d,0xb7,0x8f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x72,0x91,0x61,0x49}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x73,0x42,0xcd,0xab}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x76,0x43,0xc9,0x28}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x76,0x64,0x56,0xf6}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x76,0x6e,0x68,0x98}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x77,0xe0,0x40,0x8d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x78,0x37,0xc1,0x88}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7a,0x6a,0xa9,0xb2}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7b,0xcb,0xae,0x0f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7b,0xff,0xe8,0x5e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7c,0x94,0xa5,0xa5}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7c,0xe8,0x8d,0x1f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x80,0x1e,0x5c,0x45}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x80,0x27,0x8d,0xb6}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x80,0x54,0xa7,0x14}, 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,0x7f,0x26,0xc3}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x80,0x8c,0xe0,0xa2}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x80,0xc7,0x65,0x68}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x80,0xe9,0xe0,0x23}, 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,0x82,0xb4,0xe4,0x8a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x82,0xb9,0x90,0xd5}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x82,0xff,0x49,0xcf}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x85,0xda,0xe9,0x0b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x86,0xf9,0x80,0x17}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x88,0x9f,0xea,0xea}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x76,0xc2,0xe2,0xa8}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x77,0x1c,0x46,0x90}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x78,0x18,0xa6,0x49}, 9998},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x78,0x4c,0xf4,0xc9}, 10022},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x79,0x52,0x04,0xe8}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x79,0xfe,0xad,0x28}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7b,0xcb,0xa3,0x80}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7c,0xab,0x46,0x2d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7d,0x3f,0x39,0x07}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7d,0x80,0x23,0x29}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x80,0xd0,0xf4,0x7c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x80,0xe6,0xd0,0x49}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x83,0x72,0x0a,0xe9}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x83,0x72,0x0a,0xeb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x84,0xef,0x24,0x69}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x86,0xd5,0xd6,0xe9}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x88,0x3d,0xee,0x79}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x88,0x3e,0x56,0x8c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x88,0x90,0x80,0x31}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x89,0x30,0x90,0x34}, 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,0x8b,0xa2,0x02,0x91}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8b,0xa2,0x17,0x75}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8d,0x86,0x45,0xfd}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8d,0xff,0xa2,0xd7}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x90,0x7a,0xa3,0xbb}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x91,0x83,0x03,0x36}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x91,0xff,0x04,0x5e}, 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,0x53,0x48,0x5b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x94,0x67,0x1c,0x44}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x95,0x05,0x20,0x66}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x95,0xd2,0xa4,0xc3}, 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,0x98,0x03,0x88,0x38}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9a,0x14,0xd0,0x19}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9e,0xb5,0x68,0x95}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9f,0xfd,0x60,0xe2}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa0,0x24,0x82,0xb4}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x89,0x75,0xc1,0x71}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8a,0x13,0x4f,0xd0}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8a,0x44,0x40,0x13}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8b,0x3b,0x60,0x10}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8b,0xa2,0xa0,0xe8}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8d,0x88,0x73,0xe6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8e,0x3b,0xe8,0x6f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8e,0x6f,0x02,0x4a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8e,0xa2,0x80,0x17}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8f,0x6b,0x74,0x05}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8f,0xe5,0x16,0x4a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8f,0xe5,0x24,0x47}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x90,0x02,0x69,0x3c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x90,0x4c,0xe0,0xd6}, 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,0x93,0x20,0x1e,0x19}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x93,0xe5,0x0d,0xd2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x94,0x67,0x07,0x77}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x96,0x65,0x72,0xc2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x96,0xe5,0x00,0x8f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9a,0x42,0xcf,0x7e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9e,0x81,0xd4,0xec}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9e,0x81,0xd4,0xfb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa0,0x10,0xce,0x1f}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xd1,0x01,0xe9}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xd1,0x04,0x7d}, 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,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,0xa3,0x2c,0x02,0x30}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa3,0x9e,0x24,0x11}, 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,0x24,0x3e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa7,0xa0,0xa9,0x5c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa8,0x5d,0x81,0xdc}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa9,0x37,0x63,0x54}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa9,0xe4,0x42,0x2b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xac,0x09,0xa9,0xf2}, 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,0xe6,0xe4,0x88}, 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,0xfe,0xeb,0x22}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xae,0x00,0x80,0xde}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xae,0x19,0x82,0x94}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xae,0x32,0x40,0x65}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xaf,0x8c,0xe8,0x8d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xdc,0xf6,0xe1}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa3,0xac,0xda,0xba}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa6,0xe6,0x46,0x91}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa8,0xeb,0x4a,0x2d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa9,0x2c,0x22,0x58}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xaa,0x4b,0xc3,0xa8}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xac,0x70,0x02,0x43}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0x5e,0xa4,0x26}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xb7,0xe8,0x6d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xd0,0xb0,0x7a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xd4,0xc2,0x72}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xe8,0xe4,0x92}, 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,0xaf,0x91,0x6d,0x33}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x18,0xc6,0xcd}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x24,0x25,0x3e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x2e,0x09,0x60}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x7c,0x6e,0x1b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb1,0x27,0x10,0x66}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x11,0xad,0x02}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x3e,0x05,0xf8}, 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,0xcb,0xb9}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x4f,0xa0,0x76}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xa9,0xce,0xf4}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xc1,0xea,0x3e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xc7,0x60,0x6c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xfe,0x12,0x60}, 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,0xb2,0xff,0x29,0x7b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb4,0xd2,0x22,0x3a}, 9801},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb6,0x5c,0xe2,0xd4}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb6,0xab,0xf6,0x8e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb8,0x17,0x08,0x09}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb8,0x3a,0xa2,0x23}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb8,0x9a,0x09,0xaa}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x08,0xee,0xa5}, 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,0x6a,0x90,0xb7}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb1,0x21,0x01,0x28}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xa2,0xd6,0xe1}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xa4,0x6d,0x53}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xaa,0x8a,0xca}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xaf,0x88,0x7a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xda,0xd1,0xa2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xfe,0x02,0x40}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xfe,0x22,0x90}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xff,0x29,0x15}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xff,0x90,0xa3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb4,0xb5,0xd0,0x2a}, 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,0xb4,0xeb,0x32,0x0e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb5,0xd7,0x94,0x9a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb8,0x40,0x0d,0x2b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb8,0x5e,0xa4,0xaa}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb8,0x98,0x6b,0xfb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb8,0xb6,0xe9,0xce}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x04,0x18,0xc7}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x14,0x63,0x31}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x18,0x61,0x0b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x1f,0x89,0x8b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x26,0x2c,0x40}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x35,0x80,0xb4}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x19,0x30,0x1b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x19,0x30,0x47}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x1a,0xc4,0xf9}, 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,0x23,0x8b,0xfa}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x29,0x71,0x45}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x32,0xd5,0x7b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x32,0xd5,0x7c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x32,0xe8,0x72}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x33,0xc0,0x28}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x35,0x81,0xf4}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x4d,0x81,0x77}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x4d,0x81,0x9c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x52,0xcb,0x5c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x14,0x61,0x12}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x7e,0x08,0x0e}, 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,0x9b,0x88,0x46}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xa6,0xe5,0x70}, 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,0xe2,0xe1,0xae}, 8010},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xf2,0xab,0x08}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xf3,0x04,0x8b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbe,0x0a,0x09,0xea}, 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,0xbe,0x51,0xa0,0xb8}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbe,0x55,0xc9,0x25}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x22,0xe3,0xe6}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x4d,0xbd,0xc8}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x7c,0xe0,0x07}, 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,0xcb,0xe4,0x47}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0xce,0xca,0x14}, 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,0x29,0xe5,0x82}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x29,0xe5,0x9c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x47,0xb1,0x64}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x4d,0x81,0xb0}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x52,0xc9,0x33}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x79,0xad,0xdf}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x8c,0xfc,0xfd}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x91,0x81,0xb8}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x91,0x82,0xa3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x9a,0x9c,0x32}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0xa2,0x7c,0x45}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0xaa,0x2a,0x02}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xba,0x95,0xc5,0x60}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x41,0xd4,0x8a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x41,0xd5,0x30}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x5d,0xd1,0xc0}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x71,0x4f,0x2d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x71,0x54,0x74}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x71,0xa4,0xe7}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x7a,0x10,0x99}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xa5,0xe0,0x1c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xaf,0xef,0xe3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xd6,0x80,0x12}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xe3,0x40,0x13}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xfd,0x02,0x7d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbd,0x2d,0xcb,0xa6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbe,0xb8,0xc6,0x22}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x97,0x91,0xfa}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0xce,0xca,0x06}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0xe4,0x65,0x9d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x02,0x4c,0x29}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x1b,0xd1,0x64}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x21,0xed,0xbb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x2e,0x53,0x11}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x31,0x2b,0xdb}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x93,0x47,0x78}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0xb3,0x41,0xe9}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0xb7,0x63,0x2e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0xc0,0x25,0x87}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0xea,0xe0,0xc3}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x3a,0x6c,0xd5}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0xbb,0x60,0x02}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0xff,0x1f,0x3b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0x24,0x06,0x65}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0x3a,0xee,0xf3}, 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,0xc3,0xef,0x01,0x42}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0x30,0xc4,0xe6}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0x32,0xc0,0xa0}, 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,0x54,0xc3,0xb3}, 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,0xcc,0xe0,0x6a}, 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,0xc9,0x6e,0x08}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc7,0xe9,0xea,0x5a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x18,0xb6,0x1b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x1c,0xce,0xc9}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x3f,0x8f,0xc5}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x47,0x6d,0x5b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x4f,0x08,0x24}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x87,0x5d,0x26}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0xba,0xa0,0xfd}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0x09,0x8c,0x86}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0x27,0xce,0x1d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0x43,0x24,0x59}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0xa9,0x63,0x52}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0xd6,0xd6,0xfd}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0xdf,0x47,0x93}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0x25,0x76,0x0b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0x36,0x71,0x7d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0x65,0x0c,0x8b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0x8f,0x0c,0x69}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0xfb,0x53,0x13}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc7,0x7f,0xe0,0x32}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc8,0x0c,0x8a,0x92}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc8,0x74,0x62,0xb9}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xca,0x3c,0x46,0x12}, 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,0xcc,0x70,0xcb,0x34}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcd,0xc8,0xf7,0x95}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcf,0xe2,0x8d,0xfd}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcf,0xff,0x2a,0xca}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd0,0x35,0xa4,0x13}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd0,0x42,0x44,0x7f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd0,0x42,0x44,0x82}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd0,0x47,0xab,0xe8}, 8341},
- {{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,0xd0,0x52,0x62,0xbd}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd0,0x55,0xc1,0x1f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd0,0x6f,0x30,0x29}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd0,0x6f,0x30,0x2d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0x22,0xe8,0x48}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc8,0x7a,0x80,0x82}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xca,0x1d,0x06,0x30}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xca,0x85,0x73,0x73}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcb,0x3b,0x11,0xa0}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcc,0x0f,0x0b,0x04}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcc,0x6f,0xf1,0xc3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcd,0xfb,0x55,0x97}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcf,0xf4,0x46,0x28}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcf,0xfe,0x32,0x48}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd0,0x4c,0x5d,0x53}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd0,0x6b,0x61,0xf2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd0,0x6e,0x49,0x6b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd0,0x76,0xeb,0xbe}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0x49,0x8e,0xe2}, 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,0x5a,0xe0,0x02}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0x5a,0xe0,0x04}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0x7e,0x62,0xae}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0x88,0x48,0x45}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0xc3,0x04,0x4a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0xc5,0x0d,0x3e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd3,0x48,0xe3,0x08}, 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,0x47,0xe9,0x7f}, 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,0xd4,0x9f,0x2c,0x32}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0x7e,0x6b,0xa6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0xb1,0x56,0x13}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0xfa,0x06,0xbe}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd2,0x01,0xdb,0x9b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd2,0xd3,0x6d,0xa5}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd2,0xdf,0x03,0x2c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd3,0x15,0x81,0x45}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x32,0x62,0xa1}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x33,0x8c,0xb7}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x38,0x6c,0x51}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x53,0x23,0xad}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x5a,0xb3,0xce}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x5d,0xe2,0x5a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x6e,0xab,0x76}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0x05,0x24,0x3a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0x39,0x21,0x0a}, 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,0x88,0x49,0x7d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0x05,0xb5,0xcd}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0x11,0x10,0xfb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0x5b,0xcd,0x86}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0x5b,0xd3,0x11}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0x9b,0x03,0xd8}, 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,0xa7,0x11,0x06}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0xdf,0x8a,0x0d}, 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,0x26,0x81,0xa4}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0x30,0xa8,0x08}, 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,0xd5,0xa8,0x0d,0x97}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0xba,0xaa,0x6d}, 8334},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0xde,0xd0,0x96}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0x20,0xd5,0x70}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0x3b,0x04,0xd4}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0x7e,0xc1,0xa3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0xc5,0x4f,0x4a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0xda,0x93,0x8c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0xe3,0x27,0x54}, 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,0xf9,0xcc,0xa1}, 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,0x0c,0x22,0x9e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x0c,0xca,0x21}, 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,0x01,0x7e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x17,0x0b,0x8a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x6f,0x42,0x4f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x9b,0xca,0xbf}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x9e,0x09,0x66}, 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,0xdc,0xf5,0xc4,0x25}, 8333},
- {{0x20,0x01,0x12,0x91,0x02,0xbf,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00}, 8333},
- {{0x20,0x01,0x16,0x20,0x0f,0x00,0x02,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x20,0x01,0x16,0x20,0x0f,0x00,0x82,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x20,0x01,0x19,0xf0,0x50,0x00,0x8d,0xe8,0x54,0x00,0x00,0xff,0xfe,0x12,0x55,0xe4}, 8333},
- {{0x20,0x01,0x19,0xf0,0x6c,0x00,0x91,0x03,0x54,0x00,0x00,0xff,0xfe,0x10,0xa8,0xd3}, 8333},
- {{0x20,0x01,0x1b,0x60,0x00,0x03,0x01,0x72,0x14,0x2b,0x6d,0xff,0xfe,0x7a,0x01,0x17}, 8333},
- {{0x20,0x01,0x04,0x10,0xa0,0x00,0x40,0x50,0x84,0x63,0x90,0xb0,0xff,0xfb,0x4e,0x58}, 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,0xd9,0x0c,0xc7,0xcf}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x17,0x02,0xb1}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x17,0x05,0x44}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x1c,0xc2,0x02}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x23,0x82,0x2a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x40,0x2f,0x8a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x65,0x48,0xf2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x91,0x51,0xe5}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0xa8,0x8f,0xa9}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0xa9,0x07,0x6f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0xb6,0xc0,0x07}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xdb,0x58,0xe8,0xe5}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xdb,0x71,0xf4,0x34}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xdc,0x82,0x80,0x3a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xdc,0xf4,0xe1,0xef}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xdd,0x8d,0x03,0x0c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xde,0xa6,0xb0,0x63}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xdf,0xfc,0xad,0x93}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x10,0x25,0x04,0xe5,0xac,0xb0,0x22,0xcd}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x10,0x78,0x18,0xa6,0x5d,0x2c,0x24,0x61}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x10,0xec,0x23,0x6a,0xbd,0x3b,0xf3,0xc0}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x18,0x6d,0x3f,0x17,0xb7,0xad,0x95,0xcf}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x18,0x70,0x02,0x42,0xac,0x03,0xaa,0xf9}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x18,0xa6,0x11,0x02,0x2a,0xbf,0xeb,0x70}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x1c,0xe5,0x24,0x8c,0x4f,0xf5,0x2b,0x1d}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x20,0x0f,0x15,0x6a,0xbc,0x77,0x3a,0xcd}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x24,0x18,0x19,0xd1,0xcd,0xdc,0xb1,0xaf}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x28,0x57,0x3d,0x78,0xaa,0xf8,0xeb,0x28}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x28,0xb2,0x1b,0x84,0x64,0xfb,0x2d,0x6a}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x2c,0x70,0x0d,0x51,0xd0,0x46,0x12,0x09}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x2c,0xac,0x2f,0xcf,0x46,0xbb,0xbe,0x0d}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x30,0x5e,0x20,0xee,0xa9,0x4f,0x6f,0x69}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x30,0xcd,0x08,0x49,0xad,0xfe,0x6e,0x67}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x34,0x5b,0x0f,0x12,0xae,0x1e,0x29,0x48}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x3c,0x40,0x14,0x6e,0x97,0x41,0x5a,0x3a}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x3c,0x9e,0x3c,0x3e,0x9d,0x6e,0x73,0x40}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x04,0x99,0x29,0xa8,0xd0,0x47,0x7e,0xa1}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x00,0x51,0x00,0x24,0x81,0xb2,0x59,0xe3}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x08,0x89,0x2d,0x7c,0xb6,0x1b,0xbf,0x0d}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x0c,0x9f,0x37,0x9c,0xad,0xd2,0xc9,0x38}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x0c,0xd6,0x2e,0xb4,0xb8,0x2b,0xad,0xdb}, 8333},
+ {{0x20,0x01,0x00,0x00,0x41,0x37,0x9e,0x76,0x0c,0xf0,0x2e,0x3a,0xb2,0x9d,0x62,0x07}, 8333},
+ {{0x20,0x01,0x00,0x00,0x53,0xaa,0x06,0x4c,0x14,0x85,0xfb,0xf9,0xa7,0x98,0x1f,0xfe}, 8333},
+ {{0x20,0x01,0x00,0x00,0x53,0xaa,0x06,0x4c,0x00,0x59,0x61,0x7f,0xa1,0x0d,0x00,0xe0}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x10,0x20,0x2c,0xd0,0x47,0x50,0xeb,0x12}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x10,0x36,0x1d,0x50,0x38,0x81,0x69,0x30}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x10,0xa4,0x27,0xd8,0x9c,0x0a,0xcf,0xa9}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x10,0xae,0x05,0xa8,0x52,0x4b,0xdc,0xc4}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x18,0x92,0x3e,0x3a,0x3f,0x74,0xaf,0xfa}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x1c,0x95,0x1a,0x60,0xd1,0xf5,0x21,0x5b}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x20,0x0b,0x16,0xef,0xb9,0xcf,0x98,0x60}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x28,0xe4,0xfb,0xff,0x32,0x37,0x09,0x92}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x2c,0xe8,0x1d,0x9e,0xb3,0xbf,0xb5,0x3e}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x30,0x0a,0x2e,0x20,0x47,0x50,0xeb,0x12}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x30,0xa2,0x1a,0xd9,0x53,0x24,0x83,0x6a}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x34,0x09,0x19,0x96,0xbc,0xac,0x24,0x1f}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x34,0x4b,0x2b,0xd4,0xbb,0x3e,0x0e,0x26}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x34,0xb3,0x11,0xdb,0xe7,0xda,0xd4,0x61}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x38,0x39,0x2e,0x0c,0xba,0x30,0x28,0x8e}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x38,0x80,0x0e,0xf4,0xb5,0xf0,0xee,0x4d}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x38,0x9f,0x00,0x52,0x9c,0x0c,0x1f,0x41}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x3c,0x73,0x30,0x4a,0x9d,0x8b,0x99,0xd5}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x3c,0xac,0x33,0xe4,0x39,0xca,0x03,0x8c}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x00,0x6f,0x36,0x67,0x53,0x98,0x53,0x8f}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x08,0x8c,0x03,0xe6,0x94,0x54,0x33,0x31}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x00,0x89,0x3b,0x55,0x9f,0xcc,0x8e,0x66}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x0c,0x9b,0x3d,0x65,0xbd,0xf4,0x5d,0x58}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfb,0x0c,0xb7,0x08,0xcc,0xb8,0xee,0x68,0x06}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfd,0x24,0xf6,0x37,0xb5,0xb9,0xd2,0x2a,0xa7}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfd,0x3c,0x63,0x08,0x2e,0xaa,0xbc,0xbd,0x39}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfd,0x3c,0xf5,0x2e,0xb7,0xc9,0x66,0x56,0x1d}, 8333},
+ {{0x20,0x01,0x00,0x00,0x5e,0xf5,0x79,0xfd,0x0c,0xf4,0x28,0xe2,0xaa,0xbd,0xb7,0x66}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xb8,0x10,0xf6,0x04,0x53,0x3c,0xa4,0x1a,0x8e}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xb8,0x14,0xdd,0x29,0x8b,0x43,0x1c,0xbf,0xec}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xb8,0x30,0x51,0x15,0x61,0xb6,0x2d,0x73,0xa5}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xb8,0x34,0x67,0x0f,0xfa,0xb6,0x12,0xe9,0xc6}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xb8,0x08,0xe8,0x1e,0x26,0xe8,0xe3,0xee,0xd7}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xb8,0x0c,0x82,0x37,0xb3,0x47,0xee,0x3a,0xe2}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x10,0x52,0x3c,0xd8,0xa8,0x9b,0x0e,0x67}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x14,0x4d,0x23,0xf3,0xab,0xcb,0x8b,0xcb}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x1c,0x2e,0x31,0xdf,0xad,0xf1,0xe6,0x16}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x1c,0x41,0x21,0x3b,0xfa,0xcc,0x9c,0x6b}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x20,0x93,0x12,0xb5,0x8c,0xbf,0x4f,0x57}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x24,0x3a,0x23,0x94,0xfd,0x91,0x71,0x2c}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x28,0x33,0x09,0xf8,0xc9,0x4c,0x68,0x81}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x2c,0x84,0x29,0xd3,0xae,0x5a,0xf6,0xf0}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x2c,0xe4,0x0d,0x50,0xcb,0x22,0x36,0x72}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x38,0x24,0x08,0x16,0xc3,0x0d,0xe9,0xd4}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x38,0x9a,0x24,0xe9,0xcb,0x5c,0xa1,0xcd}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x38,0xbd,0x08,0x8f,0x21,0x93,0x49,0x32}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x3c,0x4f,0x0c,0xb1,0xd6,0x5b,0xd7,0x75}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x3c,0x51,0x28,0x0b,0xb1,0xe9,0x0f,0xfd}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x3c,0x5a,0x02,0xe2,0x21,0x93,0x49,0x32}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x3c,0x5e,0x3e,0xbf,0x3d,0xc0,0x70,0x3a}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x04,0xc9,0x12,0xfc,0xd1,0xd9,0xdc,0x21}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x00,0x6e,0x34,0xe7,0xd0,0xa7,0x67,0x72}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x08,0xde,0x1f,0x29,0x2a,0xea,0xf9,0x6f}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x0c,0x5f,0x26,0x74,0xa4,0x67,0x78,0x7c}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x6a,0xbd,0x0c,0xc0,0x23,0xa4,0xad,0x7c,0xc9,0x98}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x20,0xc0,0x20,0x97,0xd1,0x88,0x9c,0x3b}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x24,0x20,0x0d,0xda,0x4f,0xf6,0x87,0x94}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x28,0x92,0x0f,0xcb,0x26,0xb2,0x22,0xac}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x30,0x20,0x1a,0xd7,0x26,0xb2,0x22,0xac}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x30,0xae,0x21,0x1b,0xe7,0x17,0x77,0x88}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x30,0xd0,0x6e,0xdd,0xa4,0x18,0xa9,0xe9}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x30,0xd9,0x32,0x78,0xb0,0x04,0x65,0xa7}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x38,0x7a,0x17,0xd5,0xda,0xcb,0xbd,0xf1}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x3c,0x38,0x0c,0x41,0x43,0x3c,0x7b,0x87}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x04,0x67,0x01,0x93,0xa8,0xb0,0xa1,0x22}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x0c,0x65,0xfb,0x96,0x97,0xd2,0xa9,0xb0}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x0c,0x9f,0x26,0x33,0xd1,0x69,0x99,0x99}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x78,0xcf,0x0c,0xe2,0x0a,0xba,0xd1,0x20,0x90,0xdb}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x10,0x5d,0x26,0xf2,0xa2,0x41,0x73,0x39}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x10,0x62,0x3f,0x95,0xe0,0x65,0xfc,0x21}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x10,0xa6,0x19,0xf6,0xab,0x95,0xeb,0xcb}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x14,0xe2,0x22,0xcb,0x73,0x8f,0x94,0x89}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x18,0xfb,0x3d,0xa9,0x89,0x3d,0x1d,0x57}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x1c,0xc3,0x25,0x34,0xe0,0x20,0x53,0xfa}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x20,0x6d,0x2b,0x34,0xd0,0xcb,0x9d,0xe8}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x20,0xcb,0x02,0xcb,0xb9,0xa7,0xca,0x5e}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x24,0x5c,0x27,0x53,0x43,0x82,0x70,0x4b}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x24,0xd6,0x22,0x5f,0x79,0x3b,0x0b,0xf5}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x24,0xda,0x08,0xf0,0xbb,0xf9,0x9c,0x93}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x28,0xa2,0x10,0x7b,0x43,0x8e,0xb0,0x8d}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x2c,0x16,0x0d,0x58,0xb3,0x81,0x0b,0x61}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x2c,0x68,0x30,0x68,0xcb,0x59,0x3b,0xe7}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x2c,0x90,0x38,0x55,0xb9,0x4f,0xc9,0x26}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x2c,0xa2,0x35,0x92,0xc1,0x11,0xdd,0x82}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x2c,0xce,0x1f,0x6e,0xb3,0x81,0x86,0x05}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x34,0x35,0x39,0x15,0x2b,0xcc,0x6c,0xc7}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x34,0x38,0x2b,0x9f,0xad,0x57,0xa7,0x21}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x34,0x74,0x1d,0xf1,0xe7,0x32,0xe5,0xe3}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x38,0xc4,0x37,0xaf,0xab,0x0a,0xf5,0xef}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x00,0x3a,0x39,0xfd,0xa4,0x3b,0x55,0x91}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x3c,0x9d,0x2a,0x45,0xd5,0x37,0x3b,0xd6}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x3c,0xfb,0x2c,0xf5,0x52,0x54,0x4d,0x1e}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x04,0x3f,0x03,0x37,0xad,0xb4,0x63,0x10}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x04,0x93,0x09,0x95,0xd2,0xe9,0x39,0xbe}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x00,0x5b,0x0c,0xe3,0xb2,0x75,0x92,0xab}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x08,0xa8,0x05,0x9d,0xd0,0xcb,0xd5,0x85}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x0c,0x8e,0x1b,0xa0,0xc5,0xa9,0xda,0xce}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x0c,0xdb,0x36,0x5f,0x23,0x02,0xf7,0x29}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x0c,0xf5,0x22,0x2e,0x89,0x3e,0x71,0x6c}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x90,0xd7,0x00,0xd6,0x10,0x85,0xb8,0xdd,0x41,0xc2}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x10,0x1a,0x23,0xb3,0x6b,0x98,0xf8,0x88}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x18,0x05,0x0f,0x38,0x3e,0xb2,0x21,0x21}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x18,0x58,0x16,0xf9,0x38,0x33,0xda,0x19}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x18,0xea,0x27,0x35,0xe7,0x3d,0xad,0xc5}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x1c,0x44,0x2b,0x70,0x9d,0xe7,0xa7,0xcc}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x20,0x0a,0x3f,0x95,0xbb,0x7c,0xc0,0x9f}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x20,0x0c,0x34,0x73,0xb8,0x5d,0x0d,0xdd}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x20,0x0f,0x05,0xa0,0x47,0xc6,0x55,0x07}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x20,0x97,0x20,0x4a,0x47,0xc5,0x58,0x81}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x24,0x8f,0x24,0xcd,0xaa,0xf5,0xde,0xe3}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x28,0x7d,0x16,0x8e,0x3c,0xaf,0x47,0xaf}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x28,0xc1,0x05,0x8d,0xb7,0x21,0x94,0xc1}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x2c,0x31,0x30,0xa3,0x39,0xd3,0x05,0x28}, 8188},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x2c,0x3d,0x30,0x9b,0xd2,0xdb,0x82,0x88}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x2c,0x47,0x1b,0x36,0x52,0xc1,0x3c,0x73}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x30,0x4a,0x10,0xe1,0xb7,0x39,0x82,0x2a}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x30,0xa3,0x29,0xfd,0x33,0xf6,0xea,0xab}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x34,0x27,0x85,0x9b,0xb5,0x25,0x10,0x69}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x34,0x59,0x25,0x41,0x36,0x51,0xd6,0x75}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x04,0xf5,0x9c,0x88,0xaf,0x91,0xd3,0xd3}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x0c,0xd1,0x1d,0x54,0xb8,0x0a,0x42,0xf4}, 8333},
+ {{0x20,0x01,0x00,0x00,0x9d,0x38,0x95,0x3c,0x0c,0xfa,0x37,0xe6,0x9d,0x8e,0x74,0x74}, 8333},
+ {{0x20,0x01,0x13,0xd8,0x1c,0x01,0x20,0x00,0x24,0x70,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x14,0x70,0xff,0xfd,0x20,0x2c,0x02,0x25,0x90,0xff,0xfe,0x8f,0x5f,0x62}, 8333},
+ {{0x20,0x01,0x14,0xba,0x02,0x00,0x00,0x00,0x54,0x3c,0x42,0xce,0xa4,0x8b,0xb0,0xd0}, 8333},
+ {{0x20,0x01,0x14,0xba,0x02,0xfc,0x07,0x00,0x41,0xb2,0xdf,0x51,0xef,0xd8,0xf5,0x81}, 8333},
+ {{0x20,0x01,0x19,0xf0,0x50,0x00,0x8c,0x8b,0x54,0x00,0x00,0xff,0xfe,0x1f,0xc0,0x23}, 8333},
+ {{0x20,0x01,0x19,0xf0,0x00,0x05,0x07,0x49,0x54,0x00,0x00,0xff,0xfe,0x71,0xc3,0xfc}, 8333},
+ {{0x20,0x01,0x19,0xf0,0x00,0x05,0x00,0xbc,0x54,0x00,0x00,0xff,0xfe,0x3b,0x93,0x39}, 8333},
+ {{0x20,0x01,0x19,0xf0,0x74,0x02,0x04,0x2c,0x54,0x00,0x00,0xff,0xfe,0x6c,0xb9,0xb8}, 8333},
+ {{0x20,0x01,0x1a,0xf8,0x40,0x10,0xa0,0x8f,0xf8,0x11,0xe5,0xf0,0x3f,0x63,0xe7,0x53}, 8333},
+ {{0x20,0x01,0x1a,0xf8,0x40,0x10,0xa0,0x94,0x33,0x33,0x00,0x00,0x00,0x00,0x8c,0x38}, 8333},
+ {{0x20,0x01,0x1a,0xf8,0x40,0x70,0xa0,0x16,0x33,0x33,0x00,0x00,0x00,0x00,0x5a,0xfb}, 8333},
+ {{0x20,0x01,0x1a,0xf8,0x47,0x00,0xa0,0x71,0x44,0x44,0x00,0x00,0x00,0x00,0xe2,0x6e}, 8333},
+ {{0x20,0x01,0x1b,0xc8,0x01,0xa0,0x59,0x0e,0x02,0xe0,0xf4,0xff,0xfe,0x16,0x3a,0x39}, 8333},
+ {{0x20,0x01,0x20,0x40,0x00,0x77,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x89}, 8333},
+ {{0x20,0x01,0x02,0x88,0x10,0x01,0x01,0x07,0x29,0x4e,0x55,0x81,0x74,0xbd,0x42,0xf9}, 8333},
+ {{0x20,0x01,0x03,0xc8,0xc1,0x03,0xa0,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48}, 8333},
+ {{0x20,0x01,0x41,0x28,0x61,0x35,0x00,0x10,0x02,0x0c,0x29,0xff,0xfe,0x69,0x9e,0x81}, 8333},
{{0x20,0x01,0x41,0x28,0x61,0x35,0x20,0x10,0x02,0x1e,0x0b,0xff,0xfe,0xe8,0xa3,0xc0}, 8333},
- {{0x20,0x01,0x41,0xd0,0x10,0x08,0x07,0x61,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x7c}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x01,0x45,0xd8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x01,0x6c,0xd3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0x28,0x61,0x35,0xe0,0x01,0x50,0x54,0x00,0xff,0xfe,0x37,0xe9,0xeb}, 8333},
+ {{0x20,0x01,0x41,0x78,0x00,0x06,0x14,0x27,0x00,0x62,0x01,0x16,0x01,0x88,0x00,0x85}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x10,0x04,0x20,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x10,0x08,0x27,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0x47,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0x6f,0x57,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0x73,0x53,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0x74,0x69,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0x7d,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
{{0x20,0x01,0x41,0xd0,0x00,0x01,0x8b,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x01,0xaf,0xda,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8200},
- {{0x20,0x01,0x41,0xd0,0x00,0x01,0xb2,0x6b,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,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,0x02,0x10,0x21,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,0x47,0x97,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x02,0x53,0xdf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0xc1,0x29,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0xd2,0x27,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0xe1,0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0xe6,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x02,0x16,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x02,0x20,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x02,0x32,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x02,0x8a,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x02,0x8c,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x02,0x8d,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x02,0x94,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x02,0x95,0x0a,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x03}, 8333},
{{0x20,0x01,0x41,0xd0,0x00,0x02,0x9c,0x94,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x02,0x9d,0x3e,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,0xa3,0x5a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x02,0xb2,0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x02,0xc1,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x02,0x0c,0x6e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x02,0xc9,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x02,0xf1,0xa5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x52,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x5f}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x52,0x0c,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0xf5}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x02,0xa2,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x02,0xa2,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x02,0xab,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x02,0xbf,0x2a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x02,0xc7,0x93,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x03,0x02,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfa,0x25}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x03,0x03,0x19,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
{{0x20,0x01,0x41,0xd0,0x00,0x52,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0xe2}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x08,0x3e,0x75,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x08,0x62,0xab,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x08,0x67,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x08,0xb3,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x08,0xbc,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x08,0xbe,0x9a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x08,0xd9,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x08,0xeb,0x8b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x13,0xa2,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,0x2d,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x45,0x58,0x00,0x00,0x00,0x00,0x1d,0xf2,0x76,0xd3}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x4a,0xaa,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x52,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0xe3}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0x1b,0x29,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0x3d,0x4b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0x4d,0x4d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0x7a,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0x8f,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0xba,0x87,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0xbd,0x45,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0xbe,0xd3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0xc6,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0xd8,0x44,0x13,0x37,0x00,0x00,0x00,0x00,0x10,0x17}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0x0d,0xdb,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0x0d,0xdf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0xde,0x3d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0xe3,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x4e,0x3f,0x00,0x00,0x00,0x00,0x1c,0x7d,0x6b,0x01}, 8333},
{{0x20,0x01,0x41,0xd0,0x00,0x0a,0x63,0x5b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x63,0xd8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x68,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
{{0x20,0x01,0x41,0xd0,0x00,0x0a,0x6c,0x29,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x0a,0xf9,0xcd,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x0d,0x20,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
- {{0x20,0x01,0x41,0xd0,0x00,0x0e,0x02,0x6b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x20,0x01,0x41,0xd0,0xfc,0x8c,0xa2,0x00,0x7a,0x24,0xaf,0xff,0xfe,0x9d,0xc6,0x9b}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x6f,0xd0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x0a,0xfa,0xc7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x0d,0x11,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x0d,0x2a,0xc8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x0e,0x13,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xf0,0x00,0x61,0x00,0x00,0x72,0xf3,0x95,0xff,0xfe,0x09,0x75,0x21}, 8333},
{{0x20,0x01,0x41,0xf0,0x00,0x61,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07}, 8333},
- {{0x20,0x01,0x41,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x20,0x01,0x44,0xb8,0x41,0xbd,0x61,0x01,0x14,0x8e,0x40,0x22,0x49,0x50,0xe8,0x61}, 8333},
- {{0x20,0x01,0x04,0x70,0x00,0x01,0x02,0xf9,0x00,0x00,0x00,0x01,0x10,0x7a,0xa3,0x01}, 8333},
- {{0x20,0x01,0x04,0x70,0x1f,0x0b,0x0a,0xd6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x20,0x01,0x04,0x70,0x1f,0x11,0x12,0xd5,0x00,0x00,0x00,0x00,0x0a,0xe1,0x56,0x11}, 8333},
- {{0x20,0x01,0x04,0x70,0x1f,0x14,0x00,0x7d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x20,0x01,0x04,0x70,0x00,0x27,0x00,0xce,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x20,0x01,0x04,0x70,0x00,0x41,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x20,0x01,0x04,0x70,0x50,0x7d,0x00,0x00,0x6a,0xb5,0x99,0xff,0xfe,0x73,0xac,0x18}, 8333},
- {{0x20,0x01,0x04,0x70,0x58,0x3e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2a}, 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,0x6c,0x4f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xca,0xfe}, 8333},
- {{0x20,0x01,0x04,0x70,0x00,0x6f,0x03,0x27,0x91,0x3b,0x07,0xfe,0x85,0x45,0xa4,0xf5}, 8333},
+ {{0x20,0x01,0x04,0x70,0x1f,0x07,0x15,0x1c,0xba,0xac,0x6f,0xff,0xfe,0xb7,0x3b,0xa9}, 8333},
+ {{0x20,0x01,0x04,0x70,0x1f,0x0b,0x08,0xc4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05}, 8333},
+ {{0x20,0x01,0x04,0x70,0x1f,0x0b,0x09,0x67,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11}, 8333},
+ {{0x20,0x01,0x04,0x70,0x1f,0x15,0x11,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10}, 8333},
+ {{0x20,0x01,0x04,0x70,0x1f,0x15,0x1b,0x95,0x2c,0x3e,0x8a,0x9a,0x24,0xe1,0x70,0x84}, 8333},
+ {{0x20,0x01,0x04,0x70,0x1f,0x15,0x0f,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03}, 8333},
+ {{0x20,0x01,0x04,0x70,0x1f,0x1a,0x01,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x20,0x01,0x04,0x70,0x1f,0x1c,0x0b,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x20,0x01,0x04,0x70,0x1f,0x1d,0x03,0xa9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10}, 8333},
+ {{0x20,0x01,0x04,0x70,0x00,0x25,0x04,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x20,0x01,0x04,0x70,0x00,0x28,0x03,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04}, 8333},
+ {{0x20,0x01,0x04,0x70,0x75,0x4f,0x00,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x7a}, 8333},
+ {{0x20,0x01,0x04,0x70,0x00,0x07,0x0b,0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
{{0x20,0x01,0x04,0x70,0x7d,0xda,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 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,0x00,0x08,0x0c,0x70,0x02,0x0c,0x29,0xff,0xfe,0x6a,0x8f,0xdc}, 8333},
+ {{0x20,0x01,0x04,0x70,0x00,0x08,0x0c,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x54}, 8333},
+ {{0x20,0x01,0x04,0x70,0x00,0x0a,0x0c,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
{{0x20,0x01,0x04,0x70,0xd0,0x0d,0x00,0x00,0x36,0x64,0xa9,0xff,0xfe,0x9a,0x51,0x50}, 8333},
- {{0x20,0x01,0x04,0x70,0xfa,0xb7,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x20,0x01,0x48,0x00,0x78,0x19,0x01,0x04,0xbe,0x76,0x4e,0xff,0xfe,0x05,0xc8,0x28}, 8333},
- {{0x20,0x01,0x48,0x00,0x78,0x19,0x01,0x04,0xbe,0x76,0x4e,0xff,0xfe,0x05,0xc9,0xa0}, 8333},
+ {{0x20,0x01,0x04,0x70,0xdb,0xf2,0xaa,0xaa,0x00,0x00,0x00,0x00,0x0b,0x17,0xc0,0x1c}, 8333},
+ {{0x20,0x01,0x04,0x70,0xf4,0x57,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa6}, 8333},
{{0x20,0x01,0x48,0x01,0x78,0x19,0x00,0x74,0xb7,0x45,0xb9,0xd5,0xff,0x10,0xa6,0x1a}, 8333},
{{0x20,0x01,0x48,0x01,0x78,0x19,0x00,0x74,0xb7,0x45,0xb9,0xd5,0xff,0x10,0xaa,0xec}, 8333},
{{0x20,0x01,0x48,0x01,0x78,0x28,0x01,0x04,0xbe,0x76,0x4e,0xff,0xfe,0x10,0x13,0x25}, 8333},
- {{0x20,0x01,0x48,0x02,0x78,0x00,0x00,0x01,0xbe,0x76,0x4e,0xff,0xfe,0x20,0xf0,0x23}, 8333},
- {{0x20,0x01,0x48,0x02,0x78,0x00,0x00,0x02,0x30,0xd7,0x17,0x75,0xff,0x20,0x18,0x58}, 8333},
- {{0x20,0x01,0x48,0x02,0x78,0x00,0x00,0x02,0xbe,0x76,0x4e,0xff,0xfe,0x20,0x6c,0x26}, 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,0x98,0x0d,0xc2,0x00,0x41,0x02,0x16,0x3e,0xff,0xfe,0x56,0xf6,0x59}, 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}, 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,0x05,0xc0,0x14,0x00,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0xc7}, 8333},
- {{0x20,0x01,0x06,0x10,0x1b,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03}, 8333},
- {{0x20,0x01,0x06,0x10,0x06,0x00,0x0a,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x20,0x01,0x06,0x7c,0x26,0xb4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
- {{0x20,0x01,0x08,0xd8,0x08,0x40,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x39,0x01,0xae}, 8333},
- {{0x20,0x01,0x08,0xd8,0x09,0x65,0x4a,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x93,0x43}, 8333},
- {{0x20,0x01,0x09,0x80,0x46,0x50,0x00,0x01,0x02,0xe0,0x53,0xff,0xfe,0x13,0x24,0x49}, 8333},
+ {{0x20,0x01,0x4b,0xa0,0xca,0xfe,0x13,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x4b,0xa0,0xca,0xfe,0x04,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x05,0x58,0x60,0x45,0x00,0x23,0x18,0x30,0x89,0x6c,0xd9,0x01,0x19,0x0d}, 8333},
+ {{0x20,0x01,0x06,0x7c,0x12,0x20,0x08,0x0c,0x00,0x00,0x00,0x00,0x93,0xe5,0x0d,0xd2}, 8333},
+ {{0x20,0x01,0x06,0x7c,0x21,0x28,0xff,0xff,0x60,0x62,0x36,0xff,0xfe,0x30,0x65,0x32}, 8333},
+ {{0x20,0x01,0x08,0xd8,0x09,0x23,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x87,0x0e,0xbd}, 8333},
+ {{0x20,0x01,0x09,0x81,0x44,0x52,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00}, 8333},
{{0x20,0x01,0x09,0x81,0x00,0x46,0x00,0x01,0xba,0x27,0xeb,0xff,0xfe,0x5b,0xed,0xee}, 8333},
- {{0x20,0x01,0x09,0xc8,0x53,0xe9,0x36,0x9a,0x02,0x26,0x2d,0xff,0xfe,0x1b,0x74,0x72}, 8333},
- {{0x20,0x01,0x09,0xd8,0xca,0xfe,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x87}, 8333},
- {{0x20,0x01,0x0b,0x10,0x00,0x11,0x00,0x21,0x3e,0x07,0x54,0xff,0xfe,0x48,0x72,0x48}, 8333},
- {{0x20,0x01,0x0b,0xa8,0x01,0xf1,0xf3,0x4c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x20,0x01,0x0b,0xc8,0x23,0x10,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x20,0x01,0x0b,0xc8,0x34,0x27,0x01,0x01,0x7a,0x4f,0x08,0xbe,0x26,0x11,0x6e,0x79}, 8333},
- {{0x20,0x01,0x0b,0xc8,0x35,0x05,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x20,0x01,0x0c,0xc0,0xa0,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x1d}, 8333},
- {{0x20,0x01,0x0e,0x42,0x01,0x02,0x12,0x09,0x01,0x53,0x01,0x21,0x00,0x76,0x01,0x71}, 8333},
- {{0x20,0x02,0x17,0xea,0x14,0xeb,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0xea,0x14,0xeb}, 8333},
- {{0x20,0x02,0x02,0xf8,0x2b,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xf8,0x2b,0xc5}, 8333},
- {{0x20,0x02,0x40,0x47,0x48,0x2c,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x47,0x48,0x2c}, 8333},
- {{0x20,0x02,0x45,0xc3,0x8c,0xca,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0xc3,0x8c,0xca}, 8333},
- {{0x20,0x02,0x46,0xbb,0x8a,0x41,0x00,0x00,0x02,0x26,0xb0,0xff,0xfe,0xed,0x5f,0x12}, 8888},
- {{0x20,0x02,0x46,0xbb,0x8c,0x3c,0x00,0x00,0x8d,0x55,0x8f,0xbb,0x15,0xfa,0xf4,0xe0}, 8765},
- {{0x20,0x02,0x4c,0x48,0xa0,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x4c,0x48,0xa0,0xfe}, 8333},
- {{0x20,0x02,0x4d,0x44,0x25,0xc8,0x00,0x00,0x00,0x00,0x00,0x00,0x4d,0x44,0x25,0xc8}, 8333},
- {{0x20,0x02,0x50,0x5f,0xaa,0xa2,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x5f,0xaa,0xa2}, 8333},
- {{0x20,0x02,0x5b,0xc1,0x79,0x9d,0x00,0x00,0x00,0x00,0x00,0x00,0x5b,0xc1,0x79,0x9d}, 8333},
- {{0x20,0x02,0x6d,0xec,0x54,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x6d,0xec,0x54,0x72}, 8333},
- {{0x20,0x02,0x8c,0x6d,0x65,0x21,0x96,0x17,0x12,0xbf,0x48,0xff,0xfe,0xd8,0x17,0x24}, 8333},
- {{0x20,0x02,0xac,0x52,0x94,0xe2,0x00,0x00,0x00,0x00,0x00,0x00,0xac,0x52,0x94,0xe2}, 8333},
- {{0x20,0x02,0xaf,0x7e,0x3e,0xca,0x00,0x00,0x00,0x00,0x00,0x00,0xaf,0x7e,0x3e,0xca}, 8333},
- {{0x20,0x02,0xb0,0x09,0x20,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x09,0x20,0xc5}, 8333},
- {{0x20,0x02,0xc0,0x6f,0x39,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x6f,0x39,0xa0}, 8333},
- {{0x20,0x02,0xc2,0x3a,0x73,0x8a,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0x3a,0x73,0x8a}, 8333},
- {{0x20,0x02,0xc7,0x0f,0x74,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0xc7,0x0f,0x74,0x42}, 8333},
- {{0x20,0x02,0xce,0xc5,0xbe,0x4f,0x00,0x00,0x00,0x00,0x00,0x00,0xce,0xc5,0xbe,0x4f}, 8333},
- {{0x20,0x02,0xd1,0x49,0x9e,0x3a,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x49,0x9e,0x3a}, 8333},
- {{0x20,0x02,0xd9,0x17,0x0c,0xa5,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x17,0x0c,0xa5}, 8333},
- {{0x24,0x00,0x89,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x50,0x15,0x3f}, 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,0xa8,0x19,0x34}, 8333},
- {{0x24,0x00,0x89,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x26,0xc4,0xd6}, 8333},
- {{0x24,0x00,0x89,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0xc8,0x42,0x80}, 8333},
- {{0x24,0x00,0x89,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0xc8,0x66,0x0f}, 8333},
- {{0x24,0x01,0x18,0x00,0x78,0x00,0x01,0x02,0xbe,0x76,0x4e,0xff,0xfe,0x1c,0x05,0x59}, 8333},
- {{0x24,0x01,0x18,0x00,0x78,0x00,0x01,0x02,0xbe,0x76,0x4e,0xff,0xfe,0x1c,0x0a,0x7d}, 8333},
+ {{0x20,0x01,0x09,0x81,0xbd,0xbd,0x00,0x01,0xc5,0x06,0x7d,0x38,0x4b,0x47,0xda,0x15}, 8333},
+ {{0x20,0x01,0x09,0x85,0x79,0xaf,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35}, 8333},
+ {{0x20,0x01,0x0b,0xc8,0x22,0x5f,0x01,0x0e,0x05,0x05,0x65,0x73,0x75,0x73,0x0d,0x0a}, 8333},
+ {{0x20,0x01,0x0b,0xc8,0x32,0x3c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x53}, 8333},
+ {{0x20,0x01,0x0b,0xc8,0x32,0x3c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x04}, 8333},
+ {{0x20,0x01,0x0b,0xc8,0x32,0x3c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xca,0xfe}, 8333},
+ {{0x20,0x01,0x0b,0xc8,0x36,0x80,0x42,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x0b,0xc8,0x39,0x9f,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x02,0x01,0xe2,0x55,0x87,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xe2,0x55,0x87}, 8333},
+ {{0x20,0x02,0x01,0xe2,0x55,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xe2,0x55,0x88}, 8333},
+ {{0x20,0x02,0x2a,0x33,0x21,0xc4,0x00,0x00,0x00,0x00,0x00,0x00,0x2a,0x33,0x21,0xc4}, 8333},
+ {{0x20,0x02,0x2e,0x04,0x78,0x4b,0x00,0x00,0x00,0x00,0x00,0x00,0x2e,0x04,0x78,0x4b}, 8333},
+ {{0x20,0x02,0x2e,0xbc,0x2c,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x16}, 8333},
+ {{0x20,0x02,0x2f,0x5a,0x3c,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x2f,0x5a,0x3c,0x1c}, 10011},
+ {{0x20,0x02,0x2f,0x5a,0x56,0x2a,0x00,0x00,0x00,0x00,0x00,0x00,0x2f,0x5a,0x56,0x2a}, 8333},
+ {{0x20,0x02,0x2f,0x5b,0xa5,0xf9,0x00,0x00,0x00,0x00,0x00,0x00,0x2f,0x5b,0xa5,0xf9}, 8333},
+ {{0x20,0x02,0x31,0x41,0x02,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x31,0x41,0x02,0x8c}, 8333},
+ {{0x20,0x02,0x32,0x3f,0xa2,0xf2,0x00,0x00,0x00,0x00,0x00,0x00,0x32,0x3f,0xa2,0xf2}, 8333},
+ {{0x20,0x02,0x32,0x3f,0x0f,0xbd,0x00,0x00,0x00,0x00,0x00,0x00,0x32,0x3f,0x0f,0xbd}, 8333},
+ {{0x20,0x02,0x33,0xff,0x69,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x02,0x3e,0x6a,0x10,0x6f,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x6a,0x10,0x6f}, 8333},
+ {{0x20,0x02,0x3e,0x70,0x0b,0xbc,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x70,0x0b,0xbc}, 8333},
+ {{0x20,0x02,0x3e,0x7a,0x67,0x27,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x7a,0x67,0x27}, 8333},
+ {{0x20,0x02,0x3f,0x62,0xe6,0xbb,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x62,0xe6,0xbb}, 8333},
+ {{0x20,0x02,0x45,0x40,0x4b,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x40,0x4b,0x30}, 8333},
+ {{0x20,0x02,0x4e,0x6b,0xc7,0x45,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x02,0x50,0x52,0x4d,0x8a,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x52,0x4d,0x8a}, 8333},
+ {{0x20,0x02,0x51,0xa9,0x9c,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0xa9,0x9c,0xc9}, 8333},
+ {{0x20,0x02,0x54,0xfb,0xcb,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x02,0x5b,0xc2,0x54,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x5b,0xc2,0x54,0x28}, 8333},
+ {{0x20,0x02,0x5b,0xce,0x12,0x53,0x00,0x00,0x00,0x00,0x00,0x00,0x5b,0xce,0x12,0x53}, 8333},
+ {{0x20,0x02,0x5b,0xdb,0x19,0xe8,0x00,0x00,0x00,0x00,0x00,0x00,0x5b,0xdb,0x19,0xe8}, 8333},
+ {{0x20,0x02,0x5c,0x3f,0x39,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x5c,0x3f,0x39,0x12}, 8333},
+ {{0x20,0x02,0x5d,0xbd,0x91,0xa9,0x00,0x00,0x00,0x00,0x00,0x00,0x5d,0xbd,0x91,0xa9}, 8333},
+ {{0x20,0x02,0x5d,0xbe,0x8c,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x5d,0xbe,0x8c,0xc6}, 8333},
+ {{0x20,0x02,0x5f,0xd3,0x89,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0xd3,0x89,0x44}, 8333},
+ {{0x20,0x02,0x65,0xc8,0xa0,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x65,0xc8,0xa0,0x18}, 8333},
+ {{0x20,0x02,0x67,0x50,0xa8,0x39,0x00,0x00,0x00,0x00,0x00,0x00,0x67,0x50,0xa8,0x39}, 8333},
+ {{0x20,0x02,0x67,0xfa,0x04,0x4b,0x00,0x00,0x00,0x00,0x00,0x00,0x67,0xfa,0x04,0x4b}, 8333},
+ {{0x20,0x02,0x6a,0x0e,0x3e,0xa8,0x00,0x00,0x00,0x00,0x00,0x00,0x6a,0x0e,0x3e,0xa8}, 10011},
+ {{0x20,0x02,0x6a,0x0f,0x24,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x6a,0x0f,0x24,0x97}, 8333},
+ {{0x20,0x02,0x6d,0xec,0x5a,0xc7,0x00,0x00,0x00,0x00,0x00,0x00,0x6d,0xec,0x5a,0xc7}, 8333},
+ {{0x20,0x02,0x70,0x4a,0xd6,0xd4,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x4a,0xd6,0xd4}, 9997},
+ {{0x20,0x02,0x72,0x37,0xfc,0xf6,0x00,0x00,0x00,0x00,0x00,0x00,0x72,0x37,0xfc,0xf6}, 20188},
+ {{0x20,0x02,0x76,0xb2,0x7f,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x76,0xb2,0x7f,0x40}, 8333},
+ {{0x20,0x02,0x78,0x19,0x7e,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x19,0x7e,0x80}, 7743},
+ {{0x20,0x02,0x78,0x1b,0x8d,0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x1b,0x8d,0xb8}, 8333},
+ {{0x20,0x02,0x7b,0x38,0xcd,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7b,0x38,0xcd,0x00}, 8333},
+ {{0x20,0x02,0xac,0x52,0xb8,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0xac,0x52,0xb8,0x54}, 8333},
+ {{0x20,0x02,0xb6,0x10,0x1c,0xa3,0x00,0x00,0x00,0x00,0x00,0x00,0xb6,0x10,0x1c,0xa3}, 8333},
+ {{0x20,0x02,0xb9,0x46,0x69,0x4a,0x00,0x00,0x00,0x00,0x00,0x00,0xb9,0x46,0x69,0x4a}, 8339},
+ {{0x20,0x02,0xb9,0x94,0x91,0x67,0x00,0x00,0x00,0x00,0x00,0x00,0xb9,0x94,0x91,0x67}, 8333},
+ {{0x20,0x02,0xbc,0x28,0x6b,0x92,0x00,0x00,0x00,0x00,0x00,0x00,0xbc,0x28,0x6b,0x92}, 8333},
+ {{0x20,0x02,0xc2,0x3f,0x8f,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0x3f,0x8f,0xc5}, 8333},
+ {{0x20,0x02,0xc3,0x38,0x3f,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0xc3,0x38,0x3f,0x0a}, 8333},
+ {{0x20,0x02,0xd1,0xb1,0x56,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0xb1,0x56,0x15}, 8333},
+ {{0x20,0x02,0xd2,0xd3,0x6d,0xa5,0x00,0x00,0x00,0x00,0x00,0x00,0xd2,0xd3,0x6d,0xa5}, 8333},
+ {{0x20,0x02,0xd9,0x17,0x02,0xb1,0x00,0x00,0x00,0x00,0x00,0x00,0xd9,0x17,0x02,0xb1}, 8333},
+ {{0x20,0x02,0xdb,0x71,0xf4,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0xdb,0x71,0xf4,0x34}, 8333},
+ {{0x20,0x03,0x00,0x0a,0x03,0x6f,0x4f,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x03,0x00,0x0a,0x03,0x7f,0xef,0x4f,0xde,0xad,0xba,0xbe,0xb0,0x0b,0xbe,0xef}, 8333},
+ {{0x24,0x00,0x89,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x2c,0x63,0xd8}, 8333},
+ {{0x24,0x00,0x89,0x02,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0xd5,0x9d,0x8d}, 8333},
+ {{0x24,0x01,0x25,0x00,0x02,0x03,0x00,0x10,0x01,0x53,0x01,0x20,0x01,0x56,0x00,0x83}, 8333},
+ {{0x24,0x01,0xa4,0x00,0x32,0x00,0x56,0x00,0x14,0xee,0xf3,0x61,0x4b,0xdc,0x1f,0x7c}, 8333},
+ {{0x24,0x02,0x1f,0x00,0x81,0x00,0x00,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x24,0x03,0x42,0x00,0x04,0x03,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff}, 8333},
+ {{0x24,0x05,0x98,0x00,0xb4,0x40,0x94,0x7f,0x59,0xa5,0xf3,0x79,0x18,0x76,0x85,0x8c}, 8333},
{{0x24,0x05,0xaa,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40}, 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,0x26,0xbf,0xb6}, 8333},
- {{0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x33,0x88,0xe3}, 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,0x26,0xc4,0xb8}, 8333},
- {{0x26,0x00,0x3c,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x3b,0x1f,0x76}, 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,0x61,0x28,0x9b}, 8333},
+ {{0x24,0x06,0xda,0x14,0x04,0x45,0x52,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x1a,0x58,0x81,0xfe,0x6e,0xd0,0x11,0x03}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x22,0xaa,0x25,0x85,0xfe,0x88,0x7d,0x58}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x26,0x74,0x33,0xbb,0x25,0xd6,0xcb,0xba}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x2e,0x19,0xa8,0xc7,0xa3,0x6a,0xbd,0xe0}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x3c,0xc8,0x04,0x3d,0xfb,0xcc,0x50,0x67}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x52,0x28,0x2b,0x53,0xbb,0x9a,0xed,0xf5}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x57,0x29,0x01,0x02,0x99,0x8c,0xd4,0x1a}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x59,0x1b,0x48,0x81,0x39,0x86,0x37,0x03}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x59,0xb9,0x0b,0x50,0xf4,0x7f,0xb5,0x60}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x61,0xf2,0xcf,0xb0,0x8c,0x45,0x5f,0xdd}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x63,0x56,0x68,0xe0,0x73,0xfc,0xac,0x0b}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x66,0x0e,0xf6,0xbc,0x35,0x63,0xba,0x8e}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x06,0x91,0x00,0x9e,0xf2,0xdf,0x22,0x7d}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x72,0x1c,0x83,0xd2,0x67,0x65,0x43,0x00}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x72,0x37,0x09,0xbe,0x46,0x01,0xbc,0x15}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x7a,0x3b,0xc2,0x03,0xfd,0x11,0x6c,0x7d}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x7a,0x74,0xa8,0x0e,0x88,0x9a,0xba,0x42}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x7e,0xe3,0xa1,0x81,0xf2,0x5c,0xfa,0x79}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x8a,0x25,0x90,0x84,0x01,0x40,0x45,0x49}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x8b,0xc0,0xc6,0xfd,0xec,0xfb,0xf0,0x74}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x91,0xce,0xd0,0xba,0x1b,0x9e,0xc2,0x7b}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x93,0x36,0x44,0xe7,0x84,0xb4,0x85,0xb9}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x93,0x6c,0xc3,0xb9,0xa1,0xd0,0x08,0x48}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x93,0xef,0x1e,0xef,0x65,0xc8,0x76,0x6d}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x94,0xe0,0x5b,0x27,0x78,0xc2,0x51,0x11}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x98,0x15,0xa2,0x02,0x18,0xa3,0x2a,0x36}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x9e,0x1b,0x13,0x5c,0x74,0x72,0x09,0xd9}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x9f,0x84,0x02,0x78,0x68,0xf5,0xb8,0xea}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xa0,0x62,0x49,0x3f,0xa6,0xf8,0xca,0x75}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xa1,0x92,0x0b,0x98,0x30,0x66,0x8f,0x11}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xa1,0xcb,0x2f,0x19,0x4a,0x54,0x38,0xc9}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xa4,0xa2,0x04,0xc9,0xc4,0x3a,0x98,0xae}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xa7,0xe9,0xcd,0x48,0xfa,0x90,0x46,0xd3}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0x0a,0x88,0x00,0x99,0x66,0x71,0xfc,0xe4}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xab,0xe1,0x2e,0x48,0xeb,0x97,0x2a,0xb5}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xac,0xf5,0x2b,0x21,0x5d,0x2a,0x6b,0x31}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xb5,0x1f,0x89,0x66,0x74,0xa5,0x6c,0x53}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xb8,0xe3,0xf3,0xca,0xe4,0x12,0xda,0xa5}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xba,0x7c,0x6d,0xa8,0xda,0x59,0xb1,0xb6}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xbe,0x04,0x6f,0x8e,0x8f,0x93,0xc5,0x55}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xc8,0x2d,0x2a,0x0b,0x31,0xa5,0xe2,0x8d}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xc9,0x93,0xeb,0x06,0xbd,0x2c,0x1e,0x65}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xd4,0xb9,0xbf,0xf8,0xc4,0xd4,0x1e,0x05}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xd7,0x0d,0xa7,0x3d,0x1d,0xdd,0x43,0x9e}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xe1,0x03,0xf4,0x56,0xb2,0x96,0x9f,0x29}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xea,0x3b,0x27,0xec,0x07,0xc2,0xae,0xbc}, 8333},
+ {{0x24,0x06,0xda,0x18,0x0f,0x7c,0x43,0x51,0xf6,0x2c,0x50,0x13,0x37,0x9b,0x36,0x3e}, 8333},
+ {{0x24,0x0b,0x00,0x10,0xca,0x20,0x00,0xf0,0x02,0x24,0xe8,0xff,0xfe,0x1f,0x60,0xd9}, 8333},
+ {{0x24,0x0b,0x02,0x50,0x01,0xe0,0x24,0x00,0xb9,0xef,0x8f,0xe3,0xa6,0x9a,0x73,0x78}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x13,0xf4,0xce,0xb6,0xa9,0xdb,0x4f,0x47}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x25,0x50,0x93,0x66,0xa5,0xd9,0x78,0xa5}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x02,0x7d,0x06,0xed,0x7c,0x8d,0x7b,0xee}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x2e,0xd6,0x8a,0x19,0x04,0xeb,0x36,0xc1}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x34,0xc7,0x2e,0x9e,0xe6,0x0e,0xf8,0x23}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x38,0xde,0x04,0x42,0x72,0xdf,0x63,0x46}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x3a,0x1e,0x87,0x8f,0x99,0x1a,0x95,0x82}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x3d,0x88,0x18,0x05,0x54,0xe3,0xf4,0xc8}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x3f,0x3e,0x58,0xbd,0xec,0x82,0x5d,0xac}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x44,0x9a,0x95,0x15,0x84,0x36,0xf4,0x07}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x4f,0x84,0x27,0x7f,0xe6,0x4d,0x1f,0x06}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x52,0x29,0xde,0x84,0x82,0x26,0x72,0x57}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x57,0x43,0x42,0xc3,0x95,0x1b,0xe9,0x7a}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x5a,0x29,0x08,0x5b,0x86,0xb5,0xfa,0x0e}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x5d,0xe8,0x08,0x1e,0x6d,0x79,0x33,0x0b}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x5f,0xca,0xad,0x1e,0x5b,0x9c,0x52,0x65}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x68,0xc4,0xca,0x1b,0x81,0x3e,0x1b,0xce}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x00,0x06,0xde,0x9e,0x7b,0x5e,0xa5,0x58}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x6c,0x72,0x1f,0xcd,0x04,0x33,0xdc,0x97}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x77,0xee,0x62,0x9f,0xbc,0x13,0xfb,0x4f}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x79,0xd0,0x85,0xd6,0x51,0x6f,0x32,0x93}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x00,0x81,0x42,0x2f,0x9e,0xf3,0x45,0x79}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x82,0x2b,0x5f,0x05,0xec,0x8d,0x48,0xc6}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x08,0x2a,0x76,0xa2,0xfd,0xc9,0x84,0x5e}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x83,0xca,0xce,0xf6,0xe0,0x4c,0x50,0xc0}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x8b,0xa2,0xa3,0x6c,0x86,0x87,0xd5,0xaa}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x8c,0x80,0x5c,0x67,0x3b,0x47,0x90,0xb3}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x8e,0xb8,0xf4,0x7f,0x6d,0x53,0xe3,0xae}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x98,0x9c,0xf8,0xf8,0xa9,0x22,0x1b,0x9a}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x98,0xc9,0x1e,0xb3,0xea,0x12,0xa8,0xf0}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0x9e,0xe5,0xa8,0xf6,0x6b,0x2a,0x86,0x6e}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xa4,0x6b,0x7b,0xd5,0x62,0x9f,0xf7,0x5c}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xa6,0x27,0x82,0x99,0x87,0x84,0xd4,0x39}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xad,0x0b,0x95,0x5e,0xb4,0xe5,0xd9,0x7d}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xae,0x82,0x71,0x17,0x9d,0x69,0x7c,0x86}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xcc,0xee,0x36,0x5a,0x43,0xf8,0xb8,0x71}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xd5,0xee,0xa3,0xe2,0x2f,0x85,0xe5,0x93}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xd5,0xf0,0x1f,0xe0,0x6b,0xd5,0x18,0xa8}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xe4,0xa7,0x5a,0xba,0xaf,0x87,0x4c,0xdb}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xe8,0xe5,0x02,0xd0,0xfb,0x6f,0x02,0xf5}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xe9,0xef,0x46,0x90,0xa5,0xac,0x92,0xbe}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xef,0xba,0x22,0x60,0x69,0x97,0xfc,0xf7}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xf1,0x07,0x2d,0x08,0x0c,0x67,0xe5,0xdd}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xf1,0xb9,0x88,0xfb,0xf3,0xdb,0xa8,0x6e}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x03,0x4a,0xfe,0x00,0xf7,0x9c,0x17,0xb7,0x6f,0x75,0x95,0xb7}, 8333},
+ {{0x26,0x00,0x1f,0x14,0x06,0xae,0xd9,0x00,0x65,0x50,0x3f,0xc5,0xe0,0x74,0xa7,0x2c}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x12,0x43,0x38,0xb3,0x0c,0xaa,0xd6,0x2e}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x16,0x6d,0xa9,0x56,0x10,0x41,0xf9,0x7d}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x35,0xf2,0x24,0x28,0xfc,0x57,0xd6,0x38}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x3c,0x75,0x33,0x3e,0x0b,0x7f,0x8c,0xc0}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x3f,0xbf,0x03,0x1f,0x1b,0x57,0x8b,0x18}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x56,0x17,0x75,0x75,0x03,0x79,0xa8,0xcc}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x58,0xfa,0xfc,0xe6,0x00,0x30,0xa5,0xdc}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x5e,0x74,0x70,0xdc,0xaf,0x78,0x6b,0x77}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x70,0x36,0xf6,0x51,0x02,0xee,0x39,0xcd}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x07,0xfc,0x90,0x04,0xe7,0xbe,0xff,0xe2}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x81,0x4a,0x23,0xf6,0xe9,0x96,0x5e,0x64}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x82,0x2c,0xa8,0x8b,0x0f,0x9c,0x57,0xe3}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x83,0x14,0xb9,0x1e,0xa7,0xba,0x07,0x02}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x88,0xbb,0xee,0x9a,0x10,0xde,0x00,0x12}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x8c,0x30,0x56,0xf5,0xa2,0x9a,0x91,0xde}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x8f,0xdf,0x65,0x17,0x77,0x18,0x8c,0x42}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x91,0xfd,0x78,0xb1,0x62,0xa3,0x01,0x93}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x93,0x0d,0x93,0xed,0x76,0xa6,0x32,0x85}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x93,0xc2,0x61,0x5f,0xa7,0x9a,0xc1,0x1f}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xa7,0x80,0x8b,0xc8,0xa1,0xf6,0xd4,0x17}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xa9,0x51,0xe6,0x63,0x40,0x46,0x8c,0x3a}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xab,0x19,0x5f,0xe3,0xf1,0x55,0x13,0x71}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xae,0xfd,0x9c,0xc7,0x00,0xd3,0x6e,0x86}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xb0,0x31,0xe8,0x6e,0x86,0x04,0x32,0x4a}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0x0b,0x6e,0x43,0x99,0x9d,0xc2,0x6b,0x45}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xb7,0xc7,0x58,0xc6,0x21,0xa1,0xfd,0x41}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xc1,0x69,0x62,0x82,0x17,0x8c,0x27,0xd6}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xc9,0x4e,0x05,0x8b,0xbd,0x35,0xd8,0x15}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xca,0xa5,0x73,0x69,0x73,0xa4,0x57,0x11}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xcd,0x15,0xb9,0xf2,0x6e,0x3e,0x6f,0xd1}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xd6,0xf3,0x07,0x75,0x66,0xb7,0x3e,0x92}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xdb,0xec,0xf7,0xd9,0x0e,0x15,0xf8,0xe0}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xdb,0xf4,0x4d,0x41,0x59,0x4e,0xbc,0x20}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xe1,0x1b,0x45,0x89,0xa0,0xc3,0x9c,0xc7}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xed,0x68,0x15,0xb0,0x3a,0x97,0xbe,0x0c}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xee,0xf3,0xbc,0xe0,0x84,0xee,0xa9,0x8b}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xef,0x3a,0xf6,0x6e,0xf0,0x59,0xd0,0x3f}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xf6,0x7c,0xd3,0x98,0x05,0xb6,0xd3,0x4f}, 8333},
+ {{0x26,0x00,0x1f,0x16,0x06,0x25,0x0e,0x00,0xfe,0x35,0x50,0x99,0x3a,0x8e,0xd1,0x23}, 8333},
+ {{0x26,0x00,0x1f,0x18,0x64,0xd9,0x16,0x03,0x6f,0x6f,0xee,0xf9,0xb5,0x95,0x19,0x58}, 8333},
+ {{0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x84,0xd6,0x50}, 8333},
+ {{0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x89,0x74,0x38}, 8333},
+ {{0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x91,0x3e,0x49}, 8333},
+ {{0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0xbb,0x98,0x1e}, 8333},
{{0x26,0x00,0x3c,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x69,0x89,0xe9}, 8333},
- {{0x26,0x00,0x3c,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x84,0xac,0x15}, 8333},
- {{0x26,0x00,0x3c,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x98,0x68,0xbb}, 8333},
- {{0x26,0x00,0x3c,0x02,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x26,0x07,0x13}, 8333},
- {{0x26,0x00,0x3c,0x02,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x26,0xc4,0x9e}, 8333},
- {{0x26,0x00,0x3c,0x02,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x84,0x97,0xd8}, 8333},
- {{0x26,0x00,0x3c,0x02,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0xc8,0x8f,0xeb}, 8333},
- {{0x26,0x00,0x3c,0x03,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x18,0xda,0x80}, 8333},
- {{0x26,0x00,0x3c,0x03,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x26,0xc4,0x9b}, 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,0x67,0x0d,0x2e}, 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,0xc8,0x4b,0xbe}, 8333},
- {{0x26,0x00,0x3c,0x03,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0xe4,0x4e,0x16}, 8333},
- {{0x26,0x01,0x01,0x8d,0x83,0x00,0x58,0xa6,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xe4}, 8333},
- {{0x26,0x01,0x02,0x40,0x46,0x00,0x40,0xc0,0x02,0x50,0x56,0xff,0xfe,0xa4,0x63,0x05}, 8333},
- {{0x26,0x01,0x05,0x81,0xc2,0x00,0xa7,0x19,0x54,0x2c,0x9c,0xd5,0x48,0x52,0xf7,0xd9}, 8333},
- {{0x26,0x01,0x06,0x47,0x49,0x00,0x85,0xf1,0xca,0x2a,0x14,0xff,0xfe,0x51,0xbb,0x35}, 8333},
- {{0x26,0x01,0x00,0xc2,0xc0,0x02,0xb3,0x00,0x54,0xa0,0x15,0xb5,0x19,0xf7,0x53,0x0d}, 8333},
- {{0x26,0x02,0x03,0x06,0xcc,0xff,0xad,0x7f,0xb1,0x16,0x52,0xbe,0x64,0xba,0xdb,0x3a}, 8333},
- {{0x26,0x02,0x00,0xae,0x19,0x82,0x94,0x00,0x08,0x46,0xf7,0x8c,0x0f,0xec,0x4d,0x57}, 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,0x75,0xd5,0xc1,0xc3}, 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,0xe8,0x01,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x9d,0x20,0x2e,0x3c}, 8333},
- {{0x26,0x02,0xff,0xea,0x10,0x01,0x07,0x2b,0x00,0x00,0x00,0x00,0x00,0x00,0x57,0x8b}, 8333},
- {{0x26,0x02,0xff,0xea,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x24,0xc4,0xd9,0xfd}, 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,0x03,0x07,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0xc9,0xde}, 8333},
- {{0x26,0x04,0x40,0x80,0x11,0x14,0x00,0x00,0x32,0x85,0xa9,0xff,0xfe,0x93,0x85,0x0c}, 8333},
- {{0x26,0x04,0x60,0x00,0xff,0xc0,0x00,0x3c,0x64,0xa3,0x94,0xd0,0x4f,0x1d,0x1d,0xa8}, 8333},
- {{0x26,0x05,0x60,0x00,0xf3,0x80,0x9a,0x01,0xba,0x09,0x8a,0xff,0xfe,0xd4,0x35,0x11}, 8333},
- {{0x26,0x05,0x60,0x01,0xe0,0x0f,0x7b,0x00,0xc5,0x87,0x6d,0x91,0x6e,0xff,0xee,0xba}, 8333},
- {{0x26,0x05,0xf7,0x00,0x00,0xc0,0x00,0x01,0x00,0x00,0x00,0x00,0x25,0xc3,0x2a,0x3e}, 8333},
- {{0x26,0x06,0x60,0x00,0xa4,0x41,0x99,0x03,0x50,0x54,0x00,0xff,0xfe,0x78,0x66,0xff}, 8333},
- {{0x26,0x07,0x53,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1c,0x83}, 9334},
- {{0x26,0x07,0x53,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa1}, 8333},
- {{0x26,0x07,0x53,0x00,0x00,0x60,0x1c,0x2f,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,0x33,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x26,0x07,0x53,0x00,0x00,0x60,0x03,0x85,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,0x65,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
- {{0x26,0x07,0x53,0x00,0x00,0x60,0x69,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
- {{0x26,0x07,0x53,0x00,0x00,0x60,0x71,0x1a,0x00,0x78,0x00,0x00,0x00,0x00,0xa7,0xb5}, 8333},
- {{0x26,0x07,0x53,0x00,0x00,0x60,0x07,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x26,0x07,0x53,0x00,0x00,0x60,0x08,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x26,0x07,0x53,0x00,0x00,0x60,0x95,0x2e,0x37,0x33,0x00,0x00,0x00,0x00,0x14,0x14}, 8333},
- {{0x26,0x07,0xf1,0xc0,0x08,0x48,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x94,0x3c}, 8333},
- {{0x26,0x07,0xf2,0xe0,0x00,0x0f,0x05,0xdf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x26,0x07,0xf7,0x48,0x12,0x00,0x00,0xf8,0x02,0x1e,0x67,0xff,0xfe,0x99,0x8f,0x07}, 8333},
- {{0x26,0x07,0xf9,0x48,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07}, 8333},
- {{0x26,0x07,0xff,0x68,0x01,0x00,0x00,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x31}, 8333},
- {{0x28,0x03,0x69,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x17}, 8333},
- {{0x2a,0x00,0x10,0x98,0x00,0x00,0x00,0x80,0x10,0x00,0x00,0x25,0x00,0x00,0x00,0x01}, 8333},
- {{0x2a,0x00,0x11,0x78,0x00,0x02,0x00,0x43,0x50,0x54,0x00,0xff,0xfe,0x84,0xf8,0x6f}, 8333},
- {{0x2a,0x00,0x11,0x78,0x00,0x02,0x00,0x43,0x50,0x54,0x00,0xff,0xfe,0xe7,0x2e,0xb6}, 8333},
- {{0x2a,0x00,0x11,0x78,0x00,0x02,0x00,0x43,0x89,0x83,0xcc,0x27,0x0d,0x72,0xd9,0x7a}, 8333},
- {{0x2a,0x00,0x13,0x28,0xe1,0x00,0xcc,0x42,0x02,0x30,0x48,0xff,0xfe,0x92,0x05,0x5c}, 8333},
- {{0x2a,0x00,0x14,0xf0,0xe0,0x00,0x80,0xd2,0xcd,0x1a,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x2a,0x00,0x16,0x30,0x00,0x02,0x18,0x02,0x01,0x88,0x01,0x22,0x00,0x91,0x00,0x11}, 8333},
- {{0x2a,0x00,0x18,0xe0,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x2a,0x00,0x18,0xe0,0x00,0x00,0xdc,0xc5,0x01,0x09,0x02,0x34,0x01,0x06,0x01,0x91}, 8333},
- {{0x2a,0x00,0x1a,0x28,0x11,0x57,0x00,0x87,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0xc7}, 8333},
- {{0x2a,0x00,0x1c,0xa8,0x00,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0xa5,0xfc,0x40,0xd1}, 8333},
- {{0x2a,0x00,0x1c,0xa8,0x00,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0xab,0x6d,0xce,0x2c}, 8333},
- {{0x2a,0x00,0x71,0x43,0x01,0x00,0x00,0x00,0x02,0x16,0x3e,0xff,0xfe,0x2e,0x74,0xa3}, 8333},
- {{0x2a,0x00,0x71,0x43,0x01,0x00,0x00,0x00,0x02,0x16,0x3e,0xff,0xfe,0xd3,0x5c,0x21}, 8333},
- {{0x2a,0x00,0x7c,0x80,0x00,0x00,0x00,0x45,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x23}, 8333},
- {{0x2a,0x00,0xdc,0xc0,0x0e,0xda,0x00,0x98,0x01,0x83,0x01,0x93,0xc3,0x82,0x6b,0xdb}, 8333},
- {{0x2a,0x00,0xdc,0xc0,0x0e,0xda,0x00,0x98,0x01,0x83,0x01,0x93,0xf7,0x2e,0xd9,0x43}, 8333},
- {{0x2a,0x00,0xf8,0x20,0x00,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xaf,0x00,0x01}, 8333},
- {{0x2a,0x00,0xf9,0x40,0x00,0x02,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x10,0x1d}, 8333},
- {{0x2a,0x00,0xf9,0x40,0x00,0x02,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x06,0xac}, 8333},
- {{0x2a,0x01,0x01,0xb0,0x79,0x99,0x04,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x31}, 8333},
- {{0x2a,0x01,0x02,0x38,0x42,0xdd,0xf9,0x00,0x7a,0x6c,0x2b,0xc6,0x40,0x41,0x0c,0x43}, 8333},
- {{0x2a,0x01,0x02,0x38,0x43,0x13,0x63,0x00,0x21,0x89,0x1c,0x97,0x69,0x6b,0x05,0xea}, 8333},
- {{0x2a,0x01,0x04,0x88,0x00,0x66,0x10,0x00,0x5c,0x33,0x91,0xf9,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,0xf8,0x01,0x00,0x34,0xce,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x00,0x34,0xe4,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,0x0e,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,0x10,0x51,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x10,0x51,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x26,0x00,0x3c,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x91,0x6a,0x29}, 8333},
+ {{0x26,0x00,0x3c,0x03,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x28,0x14,0x45}, 8333},
+ {{0x26,0x00,0x3c,0x03,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0xe0,0x23,0x3e}, 8333},
+ {{0x26,0x00,0x6c,0x55,0x72,0x00,0x02,0x4d,0x0c,0xf4,0x81,0x1c,0x7c,0xb3,0xf7,0xa7}, 8333},
+ {{0x26,0x00,0x88,0x05,0x24,0x00,0x01,0x4e,0x02,0x26,0x4a,0xff,0xfe,0x02,0x2b,0xa4}, 8333},
+ {{0x26,0x01,0x01,0x8d,0x46,0x00,0x3c,0xc2,0x20,0xe7,0xb3,0xff,0xfe,0xcf,0x0a,0x99}, 8333},
+ {{0x26,0x01,0x01,0xc2,0x17,0x02,0x52,0x41,0x04,0x7d,0x40,0x16,0xec,0x42,0x67,0x05}, 8333},
+ {{0x26,0x01,0x04,0x41,0x41,0x01,0x70,0xcd,0x04,0xe3,0x8e,0x81,0x32,0x50,0x1f,0x0b}, 8333},
+ {{0x26,0x01,0x06,0x02,0x99,0x80,0x0f,0x78,0x02,0x11,0x11,0xff,0xfe,0xc5,0x01,0xae}, 8333},
+ {{0x26,0x01,0x06,0x46,0x41,0x03,0x17,0x9f,0x58,0x09,0x1b,0xff,0xfe,0x55,0x66,0x78}, 8333},
+ {{0x26,0x02,0x00,0x4c,0x03,0x23,0xb1,0x01,0x35,0xa3,0x9d,0xe8,0x69,0x84,0xef,0x56}, 8333},
+ {{0x26,0x02,0xff,0x62,0x01,0x04,0x0a,0xc1,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x26,0x02,0xff,0xc5,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x71,0x1e}, 8333},
+ {{0x26,0x02,0xff,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x30,0x1c,0x75}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x17,0xe9,0x20,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x22,0xf8,0xf0,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x22,0xf9,0x00,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x22,0xf9,0xc0,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x22,0xf9,0xd0,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x22,0xf9,0xe0,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x22,0xfa,0x20,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x22,0xfa,0x30,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x16,0x84,0x50,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x1a,0xc4,0xb0,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x20,0x04,0x40,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x20,0x04,0x50,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x20,0x04,0x60,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x20,0x04,0xc0,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x20,0x04,0xd0,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x20,0x04,0xe0,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x20,0x04,0xf0,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x20,0x05,0x00,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x20,0x05,0x30,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x26,0x1f,0x60,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x28,0xb8,0x50,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x0a,0xd7,0xe0,0x01}, 8333},
+ {{0x26,0x05,0x4d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50}, 8333},
+ {{0x26,0x05,0x5d,0x80,0x20,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x45}, 8333},
+ {{0x26,0x05,0x98,0x80,0x00,0x00,0x09,0x53,0x02,0x25,0x90,0xff,0xfe,0xd2,0xc0,0xb4}, 8333},
+ {{0x26,0x06,0xc3,0x80,0x00,0x00,0x00,0x00,0x02,0x15,0x17,0xff,0xfe,0xb3,0x03,0xec}, 8333},
+ {{0x26,0x07,0x1c,0x00,0x00,0x0a,0x00,0x06,0x3c,0x1c,0x1b,0x0d,0x0b,0xa4,0x8e,0xa9}, 8333},
+ {{0x26,0x07,0x1c,0x00,0x00,0x0a,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00}, 8333},
+ {{0x26,0x07,0x44,0x80,0x00,0x02,0x20,0x00,0x02,0x50,0x56,0xff,0xfe,0x86,0x64,0x49}, 8333},
+ {{0x26,0x07,0x53,0x00,0x01,0x20,0x06,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x26,0x07,0x53,0x00,0x01,0x20,0x09,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x26,0x07,0x53,0x00,0x02,0x01,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x05,0x56}, 8333},
+ {{0x26,0x07,0x53,0x00,0x02,0x03,0x01,0x18,0x37,0x33,0x00,0x00,0x00,0x00,0x14,0x14}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0x10,0xaa,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0x1e,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0x1e,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0x1e,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0x02,0xd0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0x3d,0xdf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0x3f,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0x54,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0x0a,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x61,0x0f,0x4b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x26,0x07,0x90,0x00,0x00,0x00,0x00,0x01,0x50,0x54,0x00,0xff,0xfe,0x5d,0x26,0x4e}, 8333},
+ {{0x26,0x07,0xf1,0xc0,0x08,0x46,0x9a,0x00,0x00,0x00,0x00,0x00,0x00,0x87,0xd0,0x0e}, 8333},
+ {{0x26,0x07,0xf2,0xd8,0x40,0x05,0x00,0x0d,0xa8,0xa2,0xee,0xff,0xfe,0xe0,0xa8,0x59}, 8333},
+ {{0x26,0x07,0xf9,0x48,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x40}, 8333},
+ {{0x26,0x07,0xfa,0x18,0x3a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50}, 8333},
+ {{0x26,0x07,0xfe,0xa8,0x3c,0xa0,0x09,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x26,0x07,0xfe,0xa8,0x4d,0xa0,0x03,0xb0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x26,0x07,0xff,0x10,0x00,0xc5,0x05,0x02,0x02,0x25,0x90,0xff,0xfe,0x32,0xd4,0x46}, 8333},
+ {{0x26,0x07,0xff,0x28,0x90,0x05,0x00,0x01,0x00,0x00,0x00,0x00,0x25,0x67,0x57,0xe0}, 8333},
+ {{0x26,0x20,0x00,0x71,0x40,0x00,0x00,0x00,0x01,0x92,0x00,0x30,0x01,0x20,0x01,0x10}, 8333},
+ {{0x26,0x20,0x00,0xb8,0x40,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x93,0x00,0x01}, 8333},
+ {{0x28,0x00,0x01,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09}, 8333},
+ {{0x28,0x01,0x00,0x84,0x00,0x00,0x10,0x34,0x76,0xd4,0x35,0xff,0xfe,0x7f,0x50,0x33}, 8333},
+ {{0x2a,0x00,0x16,0xd8,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x5b,0x6a,0xc2,0x61}, 8333},
+ {{0x2a,0x00,0x17,0x68,0x20,0x01,0x00,0x24,0x00,0x00,0x00,0x00,0x01,0x48,0x02,0x18}, 8333},
+ {{0x2a,0x00,0x19,0xe0,0x00,0x01,0x00,0x01,0x02,0x25,0x90,0xff,0xfe,0xa5,0x0f,0xc0}, 8333},
+ {{0x2a,0x00,0x1a,0x48,0x78,0x10,0x01,0x01,0xbe,0x76,0x4e,0xff,0xfe,0x08,0xc7,0x74}, 8333},
+ {{0x2a,0x00,0x63,0x40,0x20,0x04,0x00,0x00,0x50,0x54,0x00,0xff,0xfe,0x54,0x03,0x8c}, 8333},
+ {{0x2a,0x00,0x7b,0x80,0x04,0x77,0x00,0x21,0x00,0x00,0x00,0x00,0x1c,0x8c,0x83,0xa6}, 8333},
+ {{0x2a,0x00,0x7c,0x80,0x00,0x00,0x00,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08}, 8333},
+ {{0x2a,0x00,0x7c,0x80,0x00,0x00,0x00,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07}, 8333},
+ {{0x2a,0x01,0x02,0x38,0x43,0x63,0x49,0x00,0xd8,0x5e,0xc1,0xd9,0x2b,0x32,0x61,0xd0}, 8333},
+ {{0x2a,0x01,0x04,0x88,0x00,0x66,0x10,0x00,0x53,0xa9,0x02,0x2b,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x01,0x04,0x88,0x00,0x67,0x10,0x00,0x5b,0xfa,0x55,0x26,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x01,0x04,0x88,0x00,0x67,0x10,0x00,0xb0,0x1c,0x33,0x79,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x01,0x4d,0x60,0x00,0x03,0x00,0x01,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x0a,0x1d,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x0a,0x1e,0x81,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x0a,0x22,0x61,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8833},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x0a,0x23,0x9c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 9002},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x0a,0x29,0x4a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x0a,0x31,0xd3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x0a,0x3f,0xe6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x0a,0x0b,0x2e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x0b,0x12,0xd7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x0b,0x0d,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x0b,0x0e,0x2d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x0b,0x0e,0xe1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x10,0x51,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x10,0x52,0x92,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,0x43,0xe4,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,0x82,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x21,0x23,0x4d,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,0x11,0xea,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
{{0x2a,0x01,0x04,0xf8,0x01,0x30,0x33,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x30,0x40,0xab,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 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,0x93,0x4f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x30,0x43,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x30,0x61,0x8e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x30,0x71,0xd2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x30,0x74,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x31,0x33,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
{{0x2a,0x01,0x04,0xf8,0x01,0x31,0x33,0xad,0xfe,0xa1,0x00,0x00,0x00,0x00,0x06,0x66}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x40,0x21,0x95,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x40,0x63,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x40,0x93,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x40,0x93,0xb0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x41,0x11,0x67,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,0x41,0x53,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x50,0x33,0x6a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x31,0x34,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x40,0x13,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x40,0x52,0x4a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x40,0x60,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x40,0x74,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x40,0x93,0x1a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x41,0x22,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x41,0x22,0xae,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x50,0x11,0xd4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x50,0x70,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x50,0x72,0x6b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
{{0x2a,0x01,0x04,0xf8,0x01,0x50,0x72,0xee,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x50,0x83,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 9001},
- {{0x2a,0x01,0x04,0xf8,0x01,0x51,0x21,0xca,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x51,0x41,0xc2,0x00,0x00,0x54,0x04,0xa6,0x7e,0xf2,0x50}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x51,0x51,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x51,0x52,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x54}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x51,0x63,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 9001},
- {{0x2a,0x01,0x04,0xf8,0x01,0x60,0x51,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x60,0x72,0xc5,0x00,0x00,0x00,0x00,0x28,0x58,0xe1,0xc5}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x60,0x72,0xc5,0x00,0x00,0x00,0x00,0x59,0x3b,0x60,0xd5}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x60,0x81,0x4f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x61,0x13,0xd0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x61,0x22,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x61,0x51,0xc4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x61,0x60,0xa7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x50,0x90,0xca,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x51,0x30,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x51,0x33,0x4d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x51,0x71,0x75,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x60,0x41,0xf0,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x33}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x60,0x63,0x6e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
{{0x2a,0x01,0x04,0xf8,0x01,0x61,0x70,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x61,0x91,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
{{0x2a,0x01,0x04,0xf8,0x01,0x62,0x21,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x62,0x21,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x62,0x44,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x62,0x51,0xa3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x71,0x0b,0x93,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x90,0x14,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x90,0x44,0x95,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,0xe8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x91,0x44,0xb4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x91,0x82,0x42,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,0x92,0x11,0xb2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x92,0x21,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x92,0x22,0xb3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x01,0x92,0x44,0x0b,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,0x01,0x62,0x31,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x62,0x42,0x4c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x71,0x1c,0x1b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x71,0x01,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x71,0x22,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x71,0x27,0xd6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x71,0x2f,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x71,0x0d,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x72,0x10,0xda,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x72,0x05,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x73,0x16,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x73,0x00,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x90,0x24,0xeb,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x90,0x52,0x8d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x90,0x61,0xf3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x91,0x41,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 3333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x91,0x63,0xb4,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x91,0x81,0xb7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x91,0x83,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x92,0x04,0xa5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x92,0x52,0x30,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,0x23,0xd1,0x00,0x00,0x00,0x00,0xde,0xad,0xbe,0xef}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x02,0x00,0x50,0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x02,0x00,0x51,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x02,0x00,0x53,0x89,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x02,0x00,0x53,0xe3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x02,0x00,0x63,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x02,0x00,0x63,0x96,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x02,0x00,0x63,0xaf,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x19}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x02,0x00,0x71,0xe3,0x78,0xb4,0xf3,0xff,0xfe,0xad,0xe8,0xcf}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x02,0x01,0x21,0x4c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x02,0x01,0x02,0x33,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x03}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x00,0x32,0xa6,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,0x41,0x6a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x00,0x90,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x01,0x14,0x8d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x01,0x02,0xcc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
{{0x2a,0x01,0x04,0xf8,0x02,0x01,0x03,0xe3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x01,0x53,0xcc,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,0x02,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x02,0x02,0x31,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x02,0x30,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
{{0x2a,0x01,0x04,0xf8,0x02,0x02,0x31,0xe3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x02,0x02,0x31,0xef,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x02,0x02,0x33,0x92,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,0x02,0x63,0xf4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x02,0x02,0x72,0x27,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x02,0x10,0x22,0x27,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,0x11,0x14,0xcf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x02,0x11,0x18,0x1b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x02,0x12,0x28,0x9e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x02,0x12,0x33,0xdb,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 18333},
- {{0x2a,0x01,0x04,0xf8,0x00,0xa0,0x11,0x2f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x00,0xa0,0x31,0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x00,0xa0,0x32,0x8c,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,0x0c,0x17,0x19,0xb9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x1a,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x1a,0x92,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x02,0x73,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x04,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x07,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x0b,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x01,0x04,0xf8,0x0d,0x16,0x93,0x84,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,0x06,0x80,0x00,0x10,0x00,0x10,0xf2,0xde,0xf1,0xff,0xfe,0xc9,0x0d,0xc0}, 8333},
- {{0x2a,0x01,0x07,0xc8,0xaa,0xac,0x01,0xf6,0x50,0x54,0x00,0xff,0xfe,0x30,0xe5,0x85}, 8333},
- {{0x2a,0x01,0x07,0xc8,0xaa,0xac,0x02,0x0b,0x50,0x54,0x00,0xff,0xfe,0x24,0x43,0x5e}, 8333},
- {{0x2a,0x01,0x07,0xc8,0xaa,0xac,0x04,0x3d,0x50,0x54,0x00,0xff,0xfe,0x4e,0x3d,0xd4}, 8333},
- {{0x2a,0x01,0x07,0xc8,0xaa,0xad,0x02,0x56,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x2a,0x01,0x07,0xc8,0xaa,0xb6,0x00,0xea,0x50,0x54,0x00,0xff,0xfe,0xff,0xea,0xc3}, 8333},
- {{0x2a,0x01,0x07,0xc8,0xaa,0xb9,0x00,0x5a,0x50,0x54,0x00,0xff,0xfe,0x89,0x7b,0x26}, 8333},
- {{0x2a,0x01,0x07,0xc8,0xaa,0xbc,0x02,0xc8,0x50,0x54,0x00,0xff,0xfe,0x35,0x65,0x81}, 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,0x39,0x42}, 8333},
- {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x26,0x8c,0x87}, 8333},
- {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x50,0x62,0x06}, 8333},
- {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x67,0x55,0x9d}, 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,0x89,0x11,0x43}, 8333},
- {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x98,0x25,0x05}, 8333},
- {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0xdb,0x35,0x2e}, 8333},
- {{0x2a,0x01,0x7e,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0xc8,0xd7,0xb5}, 8333},
- {{0x2a,0x01,0x0e,0x34,0xee,0x33,0x16,0x40,0xc5,0x04,0xf6,0x77,0xb2,0x8a,0xba,0x42}, 8333},
- {{0x2a,0x01,0x0e,0x35,0x2e,0x7e,0x0b,0xc0,0xe0,0x79,0xf5,0x5e,0xce,0xf3,0xb5,0xd7}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x02,0x32,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x02,0x60,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x10,0x54,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x11,0x1e,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x11,0x1e,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x12,0x18,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x21,0x0f,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x10,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x10,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x10,0x29,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x10,0x5f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x10,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x10,0x6b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x10,0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x10,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x5c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x5e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x7b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x81,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x85,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x87,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x11,0x89,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x01,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x01,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x15,0xa8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x1d,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x1f,0xf7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x22,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x07,0x3d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x07,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x07,0xa8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x07,0xa9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x07,0xe9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0x96,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0xd1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0xd2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0xda,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0xdc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x08,0xf1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x09,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x09,0x27,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x09,0x39,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x09,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x09,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x09,0x67,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x09,0x6f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x09,0x7d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x09,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x09,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0b,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0b,0x4c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0b,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x39,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x5e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0x79,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0xb1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0xf5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0c,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0d,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0d,0x1b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0d,0x67,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0d,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0d,0x81,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0e,0x2d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0e,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0e,0x4f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0e,0x5b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0e,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0f,0x69,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0f,0x76,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0f,0x77,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0f,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0f,0x89,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0f,0x8a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0f,0xd6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x0c,0x0f,0xea,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x24,0xee,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x2c,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x33,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x34,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x39,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x3b,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x3d,0x85,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x42,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x5d,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x63,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x67,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x71,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0c,0x17,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x06,0x80,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x01,0x06,0xf0,0xff,0xff,0x01,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x8d,0xcb}, 8333},
+ {{0x2a,0x01,0x07,0x9d,0xb7,0xdd,0xff,0xb4,0x5d,0x86,0x70,0xb8,0xfc,0x7f,0xf2,0x53}, 8333},
+ {{0x2a,0x01,0x07,0xa0,0x00,0x02,0x13,0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04}, 8333},
+ {{0x2a,0x01,0x07,0xa0,0x00,0x02,0x13,0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05}, 8333},
+ {{0x2a,0x01,0x07,0xa0,0x00,0x02,0x13,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03}, 8333},
+ {{0x2a,0x01,0x07,0xc8,0xaa,0xaa,0x03,0x73,0x50,0x54,0x00,0xff,0xfe,0xb3,0x29,0x47}, 8333},
+ {{0x2a,0x01,0x07,0xc8,0xaa,0xaa,0x03,0xa0,0x50,0x54,0x00,0xff,0xfe,0x8c,0x97,0x4c}, 8333},
+ {{0x2a,0x01,0x07,0xc8,0xaa,0xb0,0x04,0xb7,0x91,0x0d,0x62,0x5e,0xa1,0x3e,0xc3,0x42}, 8333},
+ {{0x2a,0x01,0x07,0xc8,0xaa,0xb5,0x03,0xe6,0x50,0x54,0x00,0xff,0xfe,0xd7,0x4e,0x54}, 8333},
+ {{0x2a,0x01,0x07,0xc8,0xaa,0xb5,0x04,0x1e,0x50,0x54,0x00,0xff,0xfe,0x38,0xf4,0xfb}, 8333},
+ {{0x2a,0x01,0x07,0xc8,0xaa,0xba,0x03,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x83,0x33}, 8333},
+ {{0x2a,0x01,0x07,0xc8,0xaa,0xbc,0x01,0x8c,0x50,0x54,0x00,0xff,0xfe,0xfd,0x3b,0x49}, 8333},
+ {{0x2a,0x01,0x07,0xc8,0xaa,0xbd,0x03,0xd5,0x50,0x54,0x00,0xff,0xfe,0x95,0xf5,0x86}, 8333},
+ {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x50,0x94,0xb8}, 8333},
+ {{0x2a,0x01,0x8e,0x01,0xb9,0x43,0x3a,0x63,0xd2,0x50,0x99,0xff,0xfe,0x1f,0x4f,0xb2}, 8333},
+ {{0x2a,0x01,0xb2,0xe0,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40}, 8333},
+ {{0x2a,0x01,0x00,0xd0,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x45}, 8333},
+ {{0x2a,0x01,0x00,0xd0,0x8f,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x0e,0x34,0xec,0x29,0xe8,0xd0,0x25,0xc7,0xc1,0xce,0xb7,0xa3,0xd2,0x38}, 8333},
+ {{0x2a,0x01,0x0e,0x34,0xec,0x4a,0xc2,0xd0,0x1c,0xf3,0x40,0xd2,0xa7,0x9f,0x39,0x01}, 8333},
+ {{0x2a,0x01,0x0e,0x34,0xee,0xd7,0x66,0x70,0xec,0x1b,0xbf,0x7c,0xb0,0x12,0x60,0x69}, 8333},
+ {{0x2a,0x01,0x0e,0x35,0x24,0x33,0xe3,0x20,0x9c,0x8e,0x6f,0xf0,0x99,0x0f,0xf0,0x6e}, 8333},
{{0x2a,0x01,0x0e,0x35,0x2e,0xe5,0x06,0x10,0x02,0x1f,0xd0,0xff,0xfe,0x4e,0x74,0x60}, 8333},
- {{0x2a,0x01,0x0e,0x35,0x8a,0x3f,0x47,0xc0,0xc6,0x17,0xfe,0xff,0xfe,0x3c,0x9f,0xbd}, 8333},
- {{0x2a,0x01,0x0e,0x35,0x8a,0xca,0x06,0xa0,0x02,0x11,0x0a,0xff,0xfe,0x5e,0x29,0x5e}, 8333},
- {{0x2a,0x02,0x01,0x80,0x00,0x0a,0x00,0x18,0x00,0x81,0x00,0x07,0x00,0x11,0x00,0x50}, 8333},
- {{0x2a,0x02,0x18,0x10,0x1d,0x87,0x6a,0x00,0x56,0x04,0xa6,0xff,0xfe,0x60,0xd8,0x7d}, 8333},
- {{0x2a,0x02,0x21,0x68,0x11,0x44,0x5c,0x01,0xd6,0x3d,0x7e,0xff,0xfe,0xdd,0x4f,0x8e}, 8333},
- {{0x2a,0x02,0x24,0x98,0x6d,0x7b,0x70,0x01,0xb5,0x08,0xb3,0x9d,0x2c,0xea,0x5b,0x7a}, 8333},
- {{0x2a,0x02,0x25,0x28,0x05,0x03,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15}, 8333},
- {{0x2a,0x02,0x25,0x28,0x00,0xfa,0x1a,0x56,0x02,0x16,0x44,0xff,0xfe,0x6a,0xd1,0x12}, 8333},
+ {{0x2a,0x02,0x12,0x05,0x50,0x51,0xa6,0x40,0xd6,0xae,0x52,0xff,0xfe,0xa3,0x00,0xac}, 8333},
+ {{0x2a,0x02,0x12,0x0b,0x2c,0x2a,0x5e,0xc0,0x10,0xdd,0x31,0xff,0xfe,0x42,0x50,0x79}, 8333},
+ {{0x2a,0x02,0x01,0x68,0x62,0x73,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x14}, 8333},
+ {{0x2a,0x02,0x01,0x80,0x00,0x06,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18}, 8333},
+ {{0x2a,0x02,0x01,0x80,0x00,0x06,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xed}, 8333},
+ {{0x2a,0x02,0x18,0x11,0xb7,0x07,0x01,0x16,0x8c,0x1f,0xc5,0xbe,0xbf,0x3a,0x54,0xdf}, 8333},
+ {{0x2a,0x02,0x20,0xc8,0x14,0x22,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa3}, 8333},
+ {{0x2a,0x02,0x21,0x68,0x0d,0x05,0x2c,0x00,0x02,0x16,0x3e,0xff,0xfe,0xf7,0xa0,0x99}, 8333},
{{0x2a,0x02,0x27,0xf8,0x20,0x12,0x00,0x00,0xe9,0xf7,0x26,0x8f,0xc4,0x41,0x61,0x29}, 8333},
- {{0x2a,0x02,0x03,0x48,0x00,0x86,0x30,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x2a,0x02,0x47,0x80,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x8a,0x01}, 8333},
- {{0x2a,0x02,0x05,0x78,0x50,0x02,0x01,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x02,0x60,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x19,0x0b,0x69,0xe3}, 8333},
- {{0x2a,0x02,0x60,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xe8,0x93,0xd9,0xd6}, 8333},
- {{0x2a,0x02,0x07,0x70,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x39}, 8333},
- {{0x2a,0x02,0x7a,0xa0,0x12,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0xde,0xb3,0x81,0xa2}, 8333},
- {{0x2a,0x02,0x80,0x10,0xb0,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x60,0x59,0xb5}, 8333},
- {{0x2a,0x02,0x81,0x0d,0x21,0xc0,0x0f,0x00,0xa2,0x48,0x1c,0xff,0xfe,0xb8,0x53,0x48}, 8333},
- {{0x2a,0x02,0x0a,0x50,0x00,0x00,0x00,0x00,0x02,0x1b,0x24,0xff,0xfe,0x93,0x4e,0x39}, 8333},
- {{0x2a,0x02,0x0a,0x80,0x00,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x02,0xc2,0x00,0x00,0x00,0x00,0x10,0x00,0x02,0x00,0x01,0x58,0x30,0x00,0x01}, 8333},
- {{0x2a,0x02,0xc2,0x00,0x00,0x00,0x00,0x10,0x00,0x02,0x00,0x05,0x46,0x92,0x00,0x01}, 8333},
- {{0x2a,0x02,0xc2,0x00,0x00,0x00,0x00,0x10,0x00,0x03,0x00,0x00,0x71,0x58,0x00,0x01}, 8333},
- {{0x2a,0x02,0xc2,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x22,0x44,0x00,0x01}, 8333},
- {{0x2a,0x02,0xc2,0x00,0x00,0x01,0x00,0x10,0x00,0x02,0x00,0x03,0x33,0x39,0x00,0x01}, 8333},
- {{0x2a,0x02,0xc2,0x00,0x00,0x01,0x00,0x10,0x00,0x02,0x00,0x03,0x78,0x44,0x00,0x01}, 8333},
- {{0x2a,0x02,0xc2,0x00,0x00,0x01,0x00,0x10,0x00,0x02,0x00,0x05,0x62,0x88,0x00,0x01}, 8333},
- {{0x2a,0x02,0xc2,0x00,0x00,0x01,0x00,0x10,0x00,0x03,0x00,0x00,0x59,0x12,0x00,0x01}, 8333},
+ {{0x2a,0x02,0x28,0x08,0x54,0x01,0x00,0x00,0x02,0x25,0x90,0xff,0xfe,0x4e,0xee,0x42}, 8333},
+ {{0x2a,0x02,0x03,0x90,0x90,0x00,0x00,0x00,0x02,0x18,0x7d,0xff,0xfe,0x10,0xbe,0x33}, 8333},
+ {{0x2a,0x02,0x7a,0xa0,0x12,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0xbd,0x4e,0x12,0x19}, 8333},
+ {{0x2a,0x02,0x7a,0xa0,0x16,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x90,0xeb,0xa2}, 8333},
+ {{0x2a,0x02,0x7a,0xa0,0x16,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0xa7,0xa2,0x7e,0x86}, 8333},
+ {{0x2a,0x02,0xc2,0x00,0x00,0x01,0x00,0x10,0x00,0x02,0x00,0x05,0x08,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x05,0x20,0x02,0x25,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17}, 8333},
+ {{0x2a,0x02,0xc2,0x05,0x20,0x08,0x02,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x05,0x20,0x10,0x54,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x05,0x30,0x01,0x67,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x05,0x30,0x01,0x77,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x02,0xc2,0x05,0x30,0x02,0x08,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x07,0x20,0x02,0x90,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x07,0x20,0x08,0x33,0x92,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x07,0x20,0x08,0x83,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x07,0x20,0x09,0x02,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x07,0x20,0x10,0x77,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x07,0x20,0x10,0x79,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x07,0x20,0x11,0x78,0x29,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x07,0x20,0x11,0x82,0x99,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x07,0x20,0x12,0x21,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x07,0x20,0x12,0x02,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x07,0x20,0x12,0x26,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x07,0x20,0x12,0x36,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x07,0x20,0x12,0x48,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x07,0x20,0x12,0x56,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x07,0x30,0x01,0x58,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x07,0x30,0x01,0x77,0x76,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x07,0x30,0x02,0x06,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xce,0x80,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x03,0x22,0x60,0x01,0x1e,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08}, 8333},
+ {{0x2a,0x03,0x22,0x60,0x01,0x1e,0x03,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03}, 8333},
{{0x2a,0x03,0x40,0x00,0x00,0x02,0x04,0x96,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08}, 8333},
- {{0x2a,0x03,0x40,0x00,0x00,0x06,0x80,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
- {{0x2a,0x03,0x40,0x00,0x00,0x06,0x80,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0xbc,0xd0}, 8333},
- {{0x2a,0x03,0x49,0x00,0xff,0xfc,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
- {{0x2a,0x03,0xb0,0xc0,0x00,0x01,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x0d,0x50,0x01}, 8333},
- {{0x2a,0x03,0x0f,0x80,0xed,0x15,0x01,0x49,0x01,0x54,0x01,0x55,0x02,0x35,0x00,0x01}, 8333},
- {{0x2a,0x03,0x0f,0x80,0xed,0x15,0x01,0x49,0x01,0x54,0x01,0x55,0x02,0x41,0x00,0x01}, 8333},
- {{0x2a,0x03,0x0f,0x80,0xed,0x16,0x0c,0xa7,0xea,0x75,0xb1,0x2d,0x02,0xaf,0x9e,0x2a}, 8333},
- {{0x2a,0x04,0x19,0x80,0x31,0x00,0x1a,0xab,0x02,0x90,0xfa,0xff,0xfe,0x70,0xa3,0xd8}, 8333},
- {{0x2a,0x04,0x19,0x80,0x31,0x00,0x1a,0xab,0xe6,0x1d,0x2d,0xff,0xfe,0x29,0xf5,0x90}, 8333},
- {{0x2a,0x04,0x2f,0x80,0x00,0x06,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x89}, 8333},
- {{0x2a,0x04,0xac,0x00,0x00,0x01,0x4a,0x0b,0x50,0x54,0x00,0xff,0xfe,0x00,0x5a,0xf5}, 8333},
- {{0x2a,0x04,0xad,0x80,0x00,0x00,0x00,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0xda}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd9,0x4a,0xaf,0xa2,0x8c,0x9d,0xf6,0x22,0x18,0x28}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xdb,0x58,0x10,0x81,0x48,0x69,0x2c,0xb3,0x0d,0x6d}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe2,0x7f,0xf3,0x20,0xef,0x72,0xaf,0x4d,0x29,0x3c}, 8333},
+ {{0x2a,0x03,0x40,0x00,0x00,0x06,0x12,0xe7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x03,0x40,0x00,0x00,0x06,0x41,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x53}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x12,0x19,0x60,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x1b,0x99,0xc0,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x1b,0x99,0xe0,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x1b,0x9a,0x30,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xf7,0x10,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xf7,0x20,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xf7,0x40,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xf7,0x50,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xf7,0x70,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xf7,0x90,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xfb,0x10,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xfb,0x20,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xfb,0x30,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xfb,0x50,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xfb,0x60,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xfb,0x80,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x23,0xff,0xb0,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x00,0x30,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x00,0x40,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x00,0xe0,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x00,0xf0,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x01,0xe0,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x02,0x20,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x02,0x80,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x02,0x90,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x02,0xb0,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x02,0xd0,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x02,0xe0,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x03,0x10,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x03,0x20,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x03,0x30,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x03,0x40,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x03,0x60,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x03,0xa0,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x03,0xb0,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x03,0xe0,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x03,0xf0,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x04,0x00,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x04,0x30,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x04,0x40,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x04,0x60,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x04,0x80,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x04,0x90,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x04,0xb0,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x05,0x20,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x05,0x30,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x05,0x80,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x05,0x90,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x05,0xa0,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x44,0xb8,0x90,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x44,0xb8,0xe0,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x44,0xb8,0xf0,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x44,0xb9,0x00,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x44,0xb9,0x10,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x44,0xb9,0x20,0x01}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x44,0xb9,0x40,0x01}, 8333},
+ {{0x2a,0x04,0x21,0x80,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94}, 8333},
+ {{0x2a,0x04,0x35,0x42,0x10,0x00,0x09,0x10,0x84,0x92,0xb8,0xff,0xfe,0x91,0x71,0x1d}, 8333},
+ {{0x2a,0x04,0x52,0xc0,0x01,0x01,0x01,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0xba,0x8e}, 8333},
+ {{0x2a,0x05,0x35,0x80,0xd4,0x00,0x14,0x0d,0xda,0x6e,0x82,0x6e,0xe7,0x71,0x41,0x00}, 8333},
+ {{0x2a,0x06,0x9f,0xc0,0x2a,0x06,0x9f,0xc0,0x2a,0x06,0x9f,0xc1,0x06,0x7c,0xe7,0x06}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd6,0xbc,0x4a,0x3c,0x6d,0x03,0xa9,0x4e,0x1f,0x55}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd1,0x62,0x6b,0xbc,0x9d,0x61,0xc8,0x63,0xe1,0xcc}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xda,0x0e,0x96,0xca,0xb6,0x16,0xef,0xe1,0xbf,0x4e}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xdd,0xbf,0xf3,0xc5,0x0b,0x37,0xa1,0xee,0x39,0xeb}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe2,0xe5,0xc7,0x79,0x12,0xc8,0x87,0xf6,0x28,0xb6}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe3,0xf6,0x00,0xa6,0xf0,0x7b,0xf3,0x74,0x7e,0x08}, 8333},
{{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xef,0x3c,0x49,0x0b,0xc1,0x74,0xc2,0x92,0x86,0xe1}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe8,0x27,0xf9,0x43,0xad,0x67,0xfd,0x74,0x25,0x43}, 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,0x07,0x9c,0x11,0x9b,0x2d,0xf7,0xd7,0xf2,0x5e,0x9b}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x00,0x7d,0xc3,0xfd,0xcb,0x7a,0xff,0x07,0xdc,0x48}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x03,0x34,0x0e,0x44,0x07,0x5c,0xcb,0x4b,0xe7,0xcb}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x06,0x69,0x75,0xcb,0x88,0x3c,0x63,0xa6,0x11,0xff}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0a,0x26,0x27,0x21,0xbf,0x0a,0x38,0xe7,0xfe,0xc1}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0a,0x26,0x27,0x21,0xae,0x94,0xd5,0xc2,0x72,0x24}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0a,0xbf,0x87,0xf8,0x8f,0x6b,0x04,0xb5,0xc3,0xfa}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0b,0x29,0x34,0x96,0x29,0xe8,0x67,0x22,0x0c,0x61}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x11,0x08,0x94,0x72,0x0f,0x2c,0xb6,0xc9,0x6f,0x22}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x12,0xc9,0x76,0x66,0x08,0x77,0xf0,0x71,0x81,0xdc}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xeb,0x24,0x59,0xe2,0x79,0x5c,0xa4,0xa8,0xf2,0x93}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xec,0xf1,0xe8,0xdd,0xe6,0x8a,0x98,0x36,0xab,0x80}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x02,0x99,0x0c,0x51,0x03,0x89,0x7b,0xe4,0x3f,0x5e}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x02,0xce,0xb2,0x1a,0x69,0x50,0xd8,0x18,0x4a,0xb3}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x08,0x0a,0xae,0xa1,0xc0,0x9a,0xcd,0x3f,0x8c,0xcb}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0d,0x1f,0xd6,0xf4,0x9b,0x55,0x23,0x54,0xe4,0xbb}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x12,0x70,0x61,0xfd,0xf4,0xea,0xe0,0xa5,0x63,0xa9}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x16,0x2a,0xf3,0x4f,0x5d,0xd7,0xf8,0x8e,0x87,0xe2}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x19,0x14,0x9e,0x58,0x02,0xc5,0x9f,0x09,0x00,0x7b}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1c,0x1f,0x7b,0x2d,0xed,0xae,0xf3,0xb3,0xe5,0xab}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1c,0x41,0x1c,0xbf,0x02,0x0c,0xef,0x60,0x89,0x63}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1c,0x5f,0xc7,0xd4,0x89,0xc0,0x6f,0xa2,0x24,0x71}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1d,0xd4,0xc9,0xb2,0xc8,0x87,0xc6,0x39,0x9a,0x8b}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x27,0x93,0xdf,0xe5,0x58,0x40,0x69,0xa9,0x30,0x03}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x22,0x45,0x02,0x56,0x89,0x14,0x17,0x38,0x37,0xe3}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x24,0x0c,0x19,0xe8,0xc7,0x2d,0x65,0x23,0x86,0xae}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x29,0x91,0x93,0x28,0x6d,0x68,0xd0,0xb7,0x79,0x40}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x2c,0x2f,0x47,0xf1,0xc4,0xae,0xf6,0x42,0x20,0x66}, 8333},
{{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x30,0x7b,0x87,0xc2,0x7e,0xd8,0xe9,0xbb,0x14,0xed}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x3e,0xaa,0xb7,0xd0,0x79,0x79,0xf3,0x0b,0xd2,0x63}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6f,0x34,0x7f,0xc7,0xce,0xa3,0x04,0x59,0x06,0x32}, 4176},
- {{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,0x7a,0x4c,0x71,0x22,0xb9,0x53,0x89,0x19,0x12,0x43}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x8d,0xbe,0xe1,0x25,0x73,0x45,0xf5,0xe6,0x10,0xad}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa5,0xa5,0xf4,0x4c,0x8f,0xfb,0xb7,0x84,0x36,0xee}, 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,0xb3,0xd1,0xf8,0xbe,0xa7,0x6b,0x46,0xbe,0xe8,0x84}, 8333}
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x31,0x87,0x8d,0x3c,0x3a,0x05,0x56,0x19,0xa6,0xd0}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x38,0x0e,0x75,0xb8,0x99,0xc1,0x60,0x7d,0x9c,0x48}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x41,0xc7,0x5f,0x07,0x39,0xd1,0xaf,0xfd,0x16,0x5f}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x43,0x7f,0x1e,0xa0,0x8e,0xfb,0x8c,0xab,0x85,0xa4}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x55,0x47,0xce,0x4a,0xdf,0x92,0x83,0xd2,0xb9,0x76}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x63,0x7f,0xce,0x1c,0x28,0x70,0x30,0xdd,0xb9,0x32}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x64,0xb8,0xd9,0xc6,0x28,0x91,0x6f,0x97,0xd5,0x98}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6f,0x57,0x0b,0x3d,0x20,0x0c,0x0d,0xed,0x20,0xf7}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x77,0x24,0xbe,0xb4,0x1e,0x49,0x20,0x64,0x6d,0x7e}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x73,0x13,0x5d,0x71,0xa1,0x12,0xb8,0xae,0xd0,0x7e}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x7b,0xb6,0x9d,0x1c,0xaa,0x61,0x7f,0x23,0xef,0xce}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x7c,0x84,0xef,0x06,0xe9,0x25,0x96,0x98,0x8b,0x37}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x82,0x3b,0x88,0xf9,0x75,0x58,0x95,0x92,0x95,0xd1}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x82,0xeb,0xe7,0xe3,0xc7,0x1c,0xf2,0x87,0xb6,0x6d}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x86,0x1a,0xc7,0x98,0x61,0x7e,0xb7,0x7c,0x15,0xa9}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x89,0xe6,0x0b,0x0a,0x5f,0xb8,0x15,0xc3,0x23,0x73}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x8a,0x40,0x2b,0x4b,0xfd,0xf8,0x11,0xef,0x2e,0x24}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x8a,0x56,0xd7,0xec,0xf6,0xac,0x64,0xc0,0x3f,0xc4}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x8a,0x87,0x58,0x0a,0x33,0x2d,0x7d,0x89,0xf1,0xd8}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x8a,0xc0,0x54,0x31,0x42,0x9d,0x73,0xed,0xad,0x66}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x8a,0xd3,0xc7,0xbd,0xca,0xe0,0xdb,0x21,0xd3,0xad}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x91,0x1d,0x25,0x50,0x79,0x57,0xaa,0xdf,0x32,0x19}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x98,0x31,0x04,0x77,0xf3,0x2a,0x31,0xfb,0xee,0xaa}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x98,0x8e,0xe7,0xfb,0xfe,0x4f,0xb0,0xf7,0xda,0xcc}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x9c,0x63,0x3c,0x3f,0x72,0x44,0x59,0x69,0xcf,0x14}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x9d,0xf9,0x91,0xfc,0x7d,0x25,0xdc,0xd6,0x85,0x67}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa7,0x08,0x20,0xfe,0x77,0xba,0x3c,0xbd,0x99,0x17}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa3,0x05,0x71,0x30,0xb8,0x15,0x48,0x9b,0x6b,0xdc}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xaf,0xef,0x01,0xf3,0x4e,0x11,0x18,0x05,0xd2,0x23}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa8,0x75,0xef,0xb2,0x7b,0x5b,0x6c,0x51,0xb0,0x61}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa9,0x2b,0xb6,0xf4,0xb7,0x2c,0x67,0x04,0xf8,0x9d}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xaa,0x24,0x4a,0xc5,0x19,0xce,0xe1,0x4c,0x00,0xc9}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xab,0xcd,0xe7,0xf4,0x9d,0x5b,0x77,0xb1,0xc2,0x6f}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xac,0x75,0x1a,0x02,0x48,0x68,0x0a,0xec,0x6c,0xab}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xbf,0x9f,0x33,0xd4,0x7d,0xbf,0x80,0x1c,0x15,0xdf}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xb8,0x6c,0x1c,0xc6,0x4f,0xa8,0x2b,0xfa,0x75,0x04}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xb9,0x44,0x4a,0xb6,0x0b,0xd0,0x8e,0xd0,0x59,0x4e}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc0,0x91,0x56,0xb9,0x9c,0xe0,0xd9,0x7b,0xf1,0xc1}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc6,0x47,0x55,0xd7,0xa3,0x02,0x26,0x02,0x91,0x4d}, 8333}
};
static SeedSpec6 pnSeed6_test[] = {
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index 13b5876530..5afe3e66b6 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -6,12 +6,12 @@
#include "chain.h"
#include "chainparams.h"
+#include "reverse_iterator.h"
#include "validation.h"
#include "uint256.h"
#include <stdint.h>
-#include <boost/foreach.hpp>
namespace Checkpoints {
@@ -19,14 +19,14 @@ namespace Checkpoints {
{
const MapCheckpoints& checkpoints = data.mapCheckpoints;
- BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints)
+ for (const MapCheckpoints::value_type& i : reverse_iterate(checkpoints))
{
const uint256& hash = i.second;
BlockMap::const_iterator t = mapBlockIndex.find(hash);
if (t != mapBlockIndex.end())
return t->second;
}
- return NULL;
+ return nullptr;
}
} // namespace Checkpoints
diff --git a/src/checkqueue.h b/src/checkqueue.h
index 32e25d5c8c..6377fbe942 100644
--- a/src/checkqueue.h
+++ b/src/checkqueue.h
@@ -5,12 +5,12 @@
#ifndef BITCOIN_CHECKQUEUE_H
#define BITCOIN_CHECKQUEUE_H
+#include "sync.h"
+
#include <algorithm>
#include <vector>
-#include <boost/foreach.hpp>
#include <boost/thread/condition_variable.hpp>
-#include <boost/thread/locks.hpp>
#include <boost/thread/mutex.hpp>
template <typename T>
@@ -119,7 +119,7 @@ private:
fOk = fAllOk;
}
// execute work
- BOOST_FOREACH (T& check, vChecks)
+ for (T& check : vChecks)
if (fOk)
fOk = check();
vChecks.clear();
@@ -127,8 +127,11 @@ private:
}
public:
+ //! Mutex to ensure only one concurrent CCheckQueueControl
+ boost::mutex ControlMutex;
+
//! Create a new check queue
- CCheckQueue(unsigned int nBatchSizeIn) : nIdle(0), nTotal(0), fAllOk(true), nTodo(0), fQuit(false), nBatchSize(nBatchSizeIn) {}
+ explicit CCheckQueue(unsigned int nBatchSizeIn) : nIdle(0), nTotal(0), fAllOk(true), nTodo(0), fQuit(false), nBatchSize(nBatchSizeIn) {}
//! Worker thread
void Thread()
@@ -146,7 +149,7 @@ public:
void Add(std::vector<T>& vChecks)
{
boost::unique_lock<boost::mutex> lock(mutex);
- BOOST_FOREACH (T& check, vChecks) {
+ for (T& check : vChecks) {
queue.push_back(T());
check.swap(queue.back());
}
@@ -161,12 +164,6 @@ public:
{
}
- bool IsIdle()
- {
- boost::unique_lock<boost::mutex> lock(mutex);
- return (nTotal == nIdle && nTodo == 0 && fAllOk == true);
- }
-
};
/**
@@ -177,22 +174,24 @@ template <typename T>
class CCheckQueueControl
{
private:
- CCheckQueue<T>* pqueue;
+ CCheckQueue<T> * const pqueue;
bool fDone;
public:
- CCheckQueueControl(CCheckQueue<T>* pqueueIn) : pqueue(pqueueIn), fDone(false)
+ CCheckQueueControl() = delete;
+ CCheckQueueControl(const CCheckQueueControl&) = delete;
+ CCheckQueueControl& operator=(const CCheckQueueControl&) = delete;
+ explicit CCheckQueueControl(CCheckQueue<T> * const pqueueIn) : pqueue(pqueueIn), fDone(false)
{
- // passed queue is supposed to be unused, or NULL
- if (pqueue != NULL) {
- bool isIdle = pqueue->IsIdle();
- assert(isIdle);
+ // passed queue is supposed to be unused, or nullptr
+ if (pqueue != nullptr) {
+ ENTER_CRITICAL_SECTION(pqueue->ControlMutex);
}
}
bool Wait()
{
- if (pqueue == NULL)
+ if (pqueue == nullptr)
return true;
bool fRet = pqueue->Wait();
fDone = true;
@@ -201,7 +200,7 @@ public:
void Add(std::vector<T>& vChecks)
{
- if (pqueue != NULL)
+ if (pqueue != nullptr)
pqueue->Add(vChecks);
}
@@ -209,6 +208,9 @@ public:
{
if (!fDone)
Wait();
+ if (pqueue != nullptr) {
+ LEAVE_CRITICAL_SECTION(pqueue->ControlMutex);
+ }
}
};
diff --git a/src/clientversion.cpp b/src/clientversion.cpp
index d2344ded09..8a4b408831 100644
--- a/src/clientversion.cpp
+++ b/src/clientversion.cpp
@@ -10,7 +10,7 @@
/**
* Name of client reported in the 'version' message. Report the same name
- * for both bitcoind and bitcoin-core, to make it harder for attackers to
+ * for both bitcoind and bitcoin-qt, to make it harder for attackers to
* target servers or GUI users specifically.
*/
const std::string CLIENT_NAME("Satoshi");
diff --git a/src/clientversion.h b/src/clientversion.h
index 0cd7e517ee..3d5392619b 100644
--- a/src/clientversion.h
+++ b/src/clientversion.h
@@ -7,29 +7,13 @@
#if defined(HAVE_CONFIG_H)
#include "config/bitcoin-config.h"
-#else
-
-/**
- * client versioning and copyright year
- */
-
-//! 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 13
-#define CLIENT_VERSION_REVISION 99
-#define CLIENT_VERSION_BUILD 0
-
-//! Set to true for release, false for prerelease or test build
-#define CLIENT_VERSION_IS_RELEASE false
-
-/**
- * Copyright year (2009-this)
- * Todo: update this when changing our copyright comments in the source
- */
-#define COPYRIGHT_YEAR 2016
-
#endif //HAVE_CONFIG_H
+// Check that required client information is defined
+#if !defined(CLIENT_VERSION_MAJOR) || !defined(CLIENT_VERSION_MINOR) || !defined(CLIENT_VERSION_REVISION) || !defined(CLIENT_VERSION_BUILD) || !defined(CLIENT_VERSION_IS_RELEASE) || !defined(COPYRIGHT_YEAR)
+#error Client version information missing: version is not defined by bitcoin-config.h or in any other way
+#endif
+
/**
* Converts the parameter X to a string after macro replacement on X has been performed.
* Don't merge these into one macro!
diff --git a/src/coins.cpp b/src/coins.cpp
index 4d0e4bc0ad..b45dfc3342 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -4,175 +4,135 @@
#include "coins.h"
+#include "consensus/consensus.h"
#include "memusage.h"
#include "random.h"
#include <assert.h>
-/**
- * calculate number of bytes for the bitmask, and its number of non-zero bytes
- * each bit in the bitmask represents the availability of one output, but the
- * availabilities of the first two outputs are encoded separately
- */
-void CCoins::CalcMaskSize(unsigned int &nBytes, unsigned int &nNonzeroBytes) const {
- unsigned int nLastUsedByte = 0;
- for (unsigned int b = 0; 2+b*8 < vout.size(); b++) {
- bool fZero = true;
- for (unsigned int i = 0; i < 8 && 2+b*8+i < vout.size(); i++) {
- if (!vout[2+b*8+i].IsNull()) {
- fZero = false;
- continue;
- }
- }
- if (!fZero) {
- nLastUsedByte = b + 1;
- nNonzeroBytes++;
- }
- }
- nBytes += nLastUsedByte;
-}
-
-bool CCoins::Spend(uint32_t nPos)
-{
- if (nPos >= vout.size() || vout[nPos].IsNull())
- return false;
- vout[nPos].SetNull();
- Cleanup();
- return true;
-}
-
-bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) const { return false; }
-bool CCoinsView::HaveCoins(const uint256 &txid) const { return false; }
+bool CCoinsView::GetCoin(const COutPoint &outpoint, Coin &coin) const { return false; }
uint256 CCoinsView::GetBestBlock() const { return uint256(); }
+std::vector<uint256> CCoinsView::GetHeadBlocks() const { return std::vector<uint256>(); }
bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; }
-CCoinsViewCursor *CCoinsView::Cursor() const { return 0; }
+CCoinsViewCursor *CCoinsView::Cursor() const { return nullptr; }
+bool CCoinsView::HaveCoin(const COutPoint &outpoint) const
+{
+ Coin coin;
+ return GetCoin(outpoint, coin);
+}
CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { }
-bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) const { return base->GetCoins(txid, coins); }
-bool CCoinsViewBacked::HaveCoins(const uint256 &txid) const { return base->HaveCoins(txid); }
+bool CCoinsViewBacked::GetCoin(const COutPoint &outpoint, Coin &coin) const { return base->GetCoin(outpoint, coin); }
+bool CCoinsViewBacked::HaveCoin(const COutPoint &outpoint) const { return base->HaveCoin(outpoint); }
uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
+std::vector<uint256> CCoinsViewBacked::GetHeadBlocks() const { return base->GetHeadBlocks(); }
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); }
CCoinsViewCursor *CCoinsViewBacked::Cursor() const { return base->Cursor(); }
+size_t CCoinsViewBacked::EstimateSize() const { return base->EstimateSize(); }
-SaltedTxidHasher::SaltedTxidHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
-
-CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), hasModifier(false), cachedCoinsUsage(0) { }
+SaltedOutpointHasher::SaltedOutpointHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
-CCoinsViewCache::~CCoinsViewCache()
-{
- assert(!hasModifier);
-}
+CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), cachedCoinsUsage(0) {}
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);
+CCoinsMap::iterator CCoinsViewCache::FetchCoin(const COutPoint &outpoint) const {
+ CCoinsMap::iterator it = cacheCoins.find(outpoint);
if (it != cacheCoins.end())
return it;
- CCoins tmp;
- if (!base->GetCoins(txid, tmp))
+ Coin tmp;
+ if (!base->GetCoin(outpoint, tmp))
return cacheCoins.end();
- CCoinsMap::iterator ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())).first;
- tmp.swap(ret->second.coins);
- if (ret->second.coins.IsPruned()) {
- // The parent only has an empty entry for this txid; we can consider our
+ CCoinsMap::iterator ret = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::forward_as_tuple(std::move(tmp))).first;
+ if (ret->second.coin.IsSpent()) {
+ // The parent only has an empty entry for this outpoint; we can consider our
// version as fresh.
ret->second.flags = CCoinsCacheEntry::FRESH;
}
- cachedCoinsUsage += ret->second.coins.DynamicMemoryUsage();
+ cachedCoinsUsage += ret->second.coin.DynamicMemoryUsage();
return ret;
}
-bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) const {
- CCoinsMap::const_iterator it = FetchCoins(txid);
+bool CCoinsViewCache::GetCoin(const COutPoint &outpoint, Coin &coin) const {
+ CCoinsMap::const_iterator it = FetchCoin(outpoint);
if (it != cacheCoins.end()) {
- coins = it->second.coins;
- return true;
+ coin = it->second.coin;
+ return !coin.IsSpent();
}
return false;
}
-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.
- ret.first->second.coins.Clear();
- ret.first->second.flags = CCoinsCacheEntry::FRESH;
- } else if (ret.first->second.coins.IsPruned()) {
- // The parent view only has a pruned entry for this; mark it as fresh.
- ret.first->second.flags = CCoinsCacheEntry::FRESH;
+void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possible_overwrite) {
+ assert(!coin.IsSpent());
+ if (coin.out.scriptPubKey.IsUnspendable()) return;
+ CCoinsMap::iterator it;
+ bool inserted;
+ std::tie(it, inserted) = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::tuple<>());
+ bool fresh = false;
+ if (!inserted) {
+ cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
+ }
+ if (!possible_overwrite) {
+ if (!it->second.coin.IsSpent()) {
+ throw std::logic_error("Adding new coin that replaces non-pruned entry");
}
- } else {
- cachedCoinUsage = ret.first->second.coins.DynamicMemoryUsage();
+ fresh = !(it->second.flags & CCoinsCacheEntry::DIRTY);
}
- // Assume that whenever ModifyCoins is called, the entry will be modified.
- ret.first->second.flags |= CCoinsCacheEntry::DIRTY;
- return CCoinsModifier(*this, ret.first, cachedCoinUsage);
+ it->second.coin = std::move(coin);
+ it->second.flags |= CCoinsCacheEntry::DIRTY | (fresh ? CCoinsCacheEntry::FRESH : 0);
+ cachedCoinsUsage += it->second.coin.DynamicMemoryUsage();
}
-/* ModifyNewCoins allows for faster coin modification when creating the new
- * outputs from a transaction. It assumes that BIP 30 (no duplicate txids)
- * applies and has already been tested for (or the test is not required due to
- * BIP 34, height in coinbase). If we can assume BIP 30 then we know that any
- * non-coinbase transaction we are adding to the UTXO must not already exist in
- * the utxo unless it is fully spent. Thus we can check only if it exists DIRTY
- * at the current level of the cache, in which case it is not safe to mark it
- * FRESH (b/c then its spentness still needs to flushed). If it's not dirty and
- * doesn't exist or is pruned in the current cache, we know it either doesn't
- * exist or is pruned in parent caches, which is the definition of FRESH. The
- * exception to this is the two historical violations of BIP 30 in the chain,
- * both of which were coinbases. We do not mark these fresh so we we can ensure
- * that they will still be properly overwritten when spent.
- */
-CCoinsModifier CCoinsViewCache::ModifyNewCoins(const uint256 &txid, bool coinbase) {
- assert(!hasModifier);
- std::pair<CCoinsMap::iterator, bool> ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry()));
- if (!coinbase) {
- // New coins must not already exist.
- if (!ret.first->second.coins.IsPruned())
- throw std::logic_error("ModifyNewCoins should not find pre-existing coins on a non-coinbase unless they are pruned!");
+void AddCoins(CCoinsViewCache& cache, const CTransaction &tx, int nHeight, bool check) {
+ bool fCoinbase = tx.IsCoinBase();
+ const uint256& txid = tx.GetHash();
+ for (size_t i = 0; i < tx.vout.size(); ++i) {
+ bool overwrite = check ? cache.HaveCoin(COutPoint(txid, i)) : fCoinbase;
+ // Always set the possible_overwrite flag to AddCoin for coinbase txn, in order to correctly
+ // deal with the pre-BIP30 occurrences of duplicate coinbase transactions.
+ cache.AddCoin(COutPoint(txid, i), Coin(tx.vout[i], nHeight, fCoinbase), overwrite);
+ }
+}
- if (!(ret.first->second.flags & CCoinsCacheEntry::DIRTY)) {
- // If the coin is known to be pruned (have no unspent outputs) in
- // the current view and the cache entry is not dirty, we know the
- // coin also must be pruned in the parent view as well, so it is safe
- // to mark this fresh.
- ret.first->second.flags |= CCoinsCacheEntry::FRESH;
- }
+bool CCoinsViewCache::SpendCoin(const COutPoint &outpoint, Coin* moveout) {
+ CCoinsMap::iterator it = FetchCoin(outpoint);
+ if (it == cacheCoins.end()) return false;
+ cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
+ if (moveout) {
+ *moveout = std::move(it->second.coin);
}
- ret.first->second.coins.Clear();
- ret.first->second.flags |= CCoinsCacheEntry::DIRTY;
- return CCoinsModifier(*this, ret.first, 0);
+ if (it->second.flags & CCoinsCacheEntry::FRESH) {
+ cacheCoins.erase(it);
+ } else {
+ it->second.flags |= CCoinsCacheEntry::DIRTY;
+ it->second.coin.Clear();
+ }
+ return true;
}
-const CCoins* CCoinsViewCache::AccessCoins(const uint256 &txid) const {
- CCoinsMap::const_iterator it = FetchCoins(txid);
+static const Coin coinEmpty;
+
+const Coin& CCoinsViewCache::AccessCoin(const COutPoint &outpoint) const {
+ CCoinsMap::const_iterator it = FetchCoin(outpoint);
if (it == cacheCoins.end()) {
- return NULL;
+ return coinEmpty;
} else {
- return &it->second.coins;
+ return it->second.coin;
}
}
-bool CCoinsViewCache::HaveCoins(const uint256 &txid) const {
- CCoinsMap::const_iterator it = FetchCoins(txid);
- // We're using vtx.empty() instead of IsPruned here for performance reasons,
- // as we only care about the case where a transaction was replaced entirely
- // in a reorganization (which wipes vout entirely, as opposed to spending
- // which just cleans individual outputs).
- return (it != cacheCoins.end() && !it->second.coins.vout.empty());
+bool CCoinsViewCache::HaveCoin(const COutPoint &outpoint) const {
+ CCoinsMap::const_iterator it = FetchCoin(outpoint);
+ return (it != cacheCoins.end() && !it->second.coin.IsSpent());
}
-bool CCoinsViewCache::HaveCoinsInCache(const uint256 &txid) const {
- CCoinsMap::const_iterator it = cacheCoins.find(txid);
- return it != cacheCoins.end();
+bool CCoinsViewCache::HaveCoinInCache(const COutPoint &outpoint) const {
+ CCoinsMap::const_iterator it = cacheCoins.find(outpoint);
+ return (it != cacheCoins.end() && !it->second.coin.IsSpent());
}
uint256 CCoinsViewCache::GetBestBlock() const {
@@ -186,19 +146,18 @@ void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
}
bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn) {
- assert(!hasModifier);
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
CCoinsMap::iterator itUs = cacheCoins.find(it->first);
if (itUs == cacheCoins.end()) {
// The parent cache does not have an entry, while the child does
// We can ignore it if it's both FRESH and pruned in the child
- if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coins.IsPruned())) {
+ if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coin.IsSpent())) {
// Otherwise we will need to create it in the parent
// and move the data up and mark it as dirty
CCoinsCacheEntry& entry = cacheCoins[it->first];
- entry.coins.swap(it->second.coins);
- cachedCoinsUsage += entry.coins.DynamicMemoryUsage();
+ entry.coin = std::move(it->second.coin);
+ cachedCoinsUsage += entry.coin.DynamicMemoryUsage();
entry.flags = CCoinsCacheEntry::DIRTY;
// We can mark it FRESH in the parent if it was FRESH in the child
// Otherwise it might have just been flushed from the parent's cache
@@ -211,21 +170,21 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
// parent cache entry has unspent outputs. If this ever happens,
// it means the FRESH flag was misapplied and there is a logic
// error in the calling code.
- if ((it->second.flags & CCoinsCacheEntry::FRESH) && !itUs->second.coins.IsPruned())
+ if ((it->second.flags & CCoinsCacheEntry::FRESH) && !itUs->second.coin.IsSpent())
throw std::logic_error("FRESH flag misapplied to cache entry for base transaction with spendable outputs");
// Found the entry in the parent cache
- if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coins.IsPruned()) {
+ if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coin.IsSpent()) {
// 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();
+ cachedCoinsUsage -= itUs->second.coin.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();
+ cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();
+ itUs->second.coin = std::move(it->second.coin);
+ cachedCoinsUsage += itUs->second.coin.DynamicMemoryUsage();
itUs->second.flags |= CCoinsCacheEntry::DIRTY;
// NOTE: It is possible the child has a FRESH flag here in
// the event the entry we found in the parent is pruned. But
@@ -249,11 +208,11 @@ bool CCoinsViewCache::Flush() {
return fOk;
}
-void CCoinsViewCache::Uncache(const uint256& hash)
+void CCoinsViewCache::Uncache(const COutPoint& hash)
{
CCoinsMap::iterator it = cacheCoins.find(hash);
if (it != cacheCoins.end() && it->second.flags == 0) {
- cachedCoinsUsage -= it->second.coins.DynamicMemoryUsage();
+ cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
cacheCoins.erase(it);
}
}
@@ -262,13 +221,6 @@ unsigned int CCoinsViewCache::GetCacheSize() const {
return cacheCoins.size();
}
-const CTxOut &CCoinsViewCache::GetOutputFor(const CTxIn& input) const
-{
- const CCoins* coins = AccessCoins(input.prevout.hash);
- assert(coins && coins->IsAvailable(input.prevout.n));
- return coins->vout[input.prevout.n];
-}
-
CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const
{
if (tx.IsCoinBase())
@@ -276,7 +228,7 @@ CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const
CAmount nResult = 0;
for (unsigned int i = 0; i < tx.vin.size(); i++)
- nResult += GetOutputFor(tx.vin[i]).nValue;
+ nResult += AccessCoin(tx.vin[i].prevout).out.nValue;
return nResult;
}
@@ -285,9 +237,7 @@ bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
{
if (!tx.IsCoinBase()) {
for (unsigned int i = 0; i < tx.vin.size(); i++) {
- const COutPoint &prevout = tx.vin[i].prevout;
- const CCoins* coins = AccessCoins(prevout.hash);
- if (!coins || !coins->IsAvailable(prevout.n)) {
+ if (!HaveCoin(tx.vin[i].prevout)) {
return false;
}
}
@@ -295,44 +245,16 @@ bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
return true;
}
-double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight, CAmount &inChainInputValue) const
-{
- inChainInputValue = 0;
- if (tx.IsCoinBase())
- return 0.0;
- double dResult = 0.0;
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
- {
- const CCoins* coins = AccessCoins(txin.prevout.hash);
- assert(coins);
- if (!coins->IsAvailable(txin.prevout.n)) continue;
- if (coins->nHeight <= nHeight) {
- dResult += (double)(coins->vout[txin.prevout.n].nValue) * (nHeight-coins->nHeight);
- inChainInputValue += coins->vout[txin.prevout.n].nValue;
- }
- }
- return tx.ComputePriority(dResult);
-}
-
-CCoinsModifier::CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_, size_t usage) : cache(cache_), it(it_), cachedCoinUsage(usage) {
- assert(!cache.hasModifier);
- cache.hasModifier = true;
-}
+static const size_t MIN_TRANSACTION_OUTPUT_WEIGHT = WITNESS_SCALE_FACTOR * ::GetSerializeSize(CTxOut(), SER_NETWORK, PROTOCOL_VERSION);
+static const size_t MAX_OUTPUTS_PER_BLOCK = MAX_BLOCK_WEIGHT / MIN_TRANSACTION_OUTPUT_WEIGHT;
-CCoinsModifier::~CCoinsModifier()
+const Coin& AccessByTxid(const CCoinsViewCache& view, const uint256& txid)
{
- 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();
+ COutPoint iter(txid, 0);
+ while (iter.n < MAX_OUTPUTS_PER_BLOCK) {
+ const Coin& alternate = view.AccessCoin(iter);
+ if (!alternate.IsSpent()) return alternate;
+ ++iter.n;
}
-}
-
-CCoinsViewCursor::~CCoinsViewCursor()
-{
+ return coinEmpty;
}
diff --git a/src/coins.h b/src/coins.h
index 902cb57f69..181b2fd4b9 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -6,6 +6,7 @@
#ifndef BITCOIN_COINS_H
#define BITCOIN_COINS_H
+#include "primitives/transaction.h"
#include "compressor.h"
#include "core_memusage.h"
#include "hash.h"
@@ -16,138 +17,39 @@
#include <assert.h>
#include <stdint.h>
-#include <boost/foreach.hpp>
-#include <boost/unordered_map.hpp>
+#include <unordered_map>
-/**
- * Pruned version of CTransaction: only retains metadata and unspent transaction outputs
+/**
+ * A UTXO entry.
*
* Serialized format:
- * - VARINT(nVersion)
- * - VARINT(nCode)
- * - unspentness bitvector, for vout[2] and further; least significant byte first
- * - the non-spent CTxOuts (via CTxOutCompressor)
- * - VARINT(nHeight)
- *
- * The nCode value consists of:
- * - bit 0: IsCoinBase()
- * - bit 1: vout[0] is not spent
- * - bit 2: vout[1] is not spent
- * - The higher bits encode N, the number of non-zero bytes in the following bitvector.
- * - In case both bit 1 and bit 2 are unset, they encode N-1, as there must be at
- * least one non-spent output).
- *
- * Example: 0104835800816115944e077fe7c803cfa57f29b36bf87c1d358bb85e
- * <><><--------------------------------------------><---->
- * | \ | /
- * version code vout[1] height
- *
- * - version = 1
- * - code = 4 (vout[1] is not spent, and 0 non-zero bytes of bitvector follow)
- * - unspentness bitvector: as 0 non-zero bytes follow, it has length 0
- * - vout[1]: 835800816115944e077fe7c803cfa57f29b36bf87c1d35
- * * 8358: compact amount representation for 60000000000 (600 BTC)
- * * 00: special txout type pay-to-pubkey-hash
- * * 816115944e077fe7c803cfa57f29b36bf87c1d35: address uint160
- * - height = 203998
- *
- *
- * Example: 0109044086ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4eebbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa486af3b
- * <><><--><--------------------------------------------------><----------------------------------------------><---->
- * / \ \ | | /
- * version code unspentness vout[4] vout[16] height
- *
- * - version = 1
- * - code = 9 (coinbase, neither vout[0] or vout[1] are unspent,
- * 2 (1, +1 because both bit 1 and bit 2 are unset) non-zero bitvector bytes follow)
- * - unspentness bitvector: bits 2 (0x04) and 14 (0x4000) are set, so vout[2+2] and vout[14+2] are unspent
- * - vout[4]: 86ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4ee
- * * 86ef97d579: compact amount representation for 234925952 (2.35 BTC)
- * * 00: special txout type pay-to-pubkey-hash
- * * 61b01caab50f1b8e9c50a5057eb43c2d9563a4ee: address uint160
- * - vout[16]: bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4
- * * bbd123: compact amount representation for 110397 (0.001 BTC)
- * * 00: special txout type pay-to-pubkey-hash
- * * 8c988f1a4a4de2161e0f50aac7f17e7f9555caa4: address uint160
- * - height = 120891
+ * - VARINT((coinbase ? 1 : 0) | (height << 1))
+ * - the non-spent CTxOut (via CTxOutCompressor)
*/
-class CCoins
+class Coin
{
public:
- //! whether transaction is a coinbase
- bool fCoinBase;
+ //! unspent transaction output
+ CTxOut out;
- //! unspent transaction outputs; spent outputs are .IsNull(); spent outputs at the end of the array are dropped
- std::vector<CTxOut> vout;
+ //! whether containing transaction was a coinbase
+ unsigned int fCoinBase : 1;
- //! at which height this transaction was included in the active block chain
- int nHeight;
+ //! at which height this containing transaction was included in the active block chain
+ uint32_t nHeight : 31;
- //! version of the CTransaction; accesses to this value should probably check for nHeight as well,
- //! as new tx version will probably only be introduced at certain heights
- int nVersion;
-
- void FromTx(const CTransaction &tx, int nHeightIn) {
- fCoinBase = tx.IsCoinBase();
- vout = tx.vout;
- nHeight = nHeightIn;
- nVersion = tx.nVersion;
- ClearUnspendable();
- }
-
- //! construct a CCoins from a CTransaction, at a given height
- CCoins(const CTransaction &tx, int nHeightIn) {
- FromTx(tx, nHeightIn);
- }
+ //! construct a Coin from a CTxOut and height/coinbase information.
+ Coin(CTxOut&& outIn, int nHeightIn, bool fCoinBaseIn) : out(std::move(outIn)), fCoinBase(fCoinBaseIn), nHeight(nHeightIn) {}
+ Coin(const CTxOut& outIn, int nHeightIn, bool fCoinBaseIn) : out(outIn), fCoinBase(fCoinBaseIn),nHeight(nHeightIn) {}
void Clear() {
+ out.SetNull();
fCoinBase = false;
- std::vector<CTxOut>().swap(vout);
nHeight = 0;
- nVersion = 0;
}
//! empty constructor
- CCoins() : fCoinBase(false), vout(0), nHeight(0), nVersion(0) { }
-
- //!remove spent outputs at the end of vout
- void Cleanup() {
- while (vout.size() > 0 && vout.back().IsNull())
- vout.pop_back();
- if (vout.empty())
- std::vector<CTxOut>().swap(vout);
- }
-
- void ClearUnspendable() {
- BOOST_FOREACH(CTxOut &txout, vout) {
- if (txout.scriptPubKey.IsUnspendable())
- txout.SetNull();
- }
- Cleanup();
- }
-
- void swap(CCoins &to) {
- std::swap(to.fCoinBase, fCoinBase);
- to.vout.swap(vout);
- std::swap(to.nHeight, nHeight);
- std::swap(to.nVersion, nVersion);
- }
-
- //! equality test
- friend bool operator==(const CCoins &a, const CCoins &b) {
- // Empty CCoins objects are always equal.
- if (a.IsPruned() && b.IsPruned())
- return true;
- return a.fCoinBase == b.fCoinBase &&
- a.nHeight == b.nHeight &&
- a.nVersion == b.nVersion &&
- a.vout == b.vout;
- }
- friend bool operator!=(const CCoins &a, const CCoins &b) {
- return !(a == b);
- }
-
- void CalcMaskSize(unsigned int &nBytes, unsigned int &nNonzeroBytes) const;
+ Coin() : fCoinBase(false), nHeight(0) { }
bool IsCoinBase() const {
return fCoinBase;
@@ -155,115 +57,52 @@ public:
template<typename Stream>
void Serialize(Stream &s) const {
- unsigned int nMaskSize = 0, nMaskCode = 0;
- CalcMaskSize(nMaskSize, nMaskCode);
- bool fFirst = vout.size() > 0 && !vout[0].IsNull();
- bool fSecond = vout.size() > 1 && !vout[1].IsNull();
- assert(fFirst || fSecond || nMaskCode);
- unsigned int nCode = 8*(nMaskCode - (fFirst || fSecond ? 0 : 1)) + (fCoinBase ? 1 : 0) + (fFirst ? 2 : 0) + (fSecond ? 4 : 0);
- // version
- ::Serialize(s, VARINT(this->nVersion));
- // header code
- ::Serialize(s, VARINT(nCode));
- // spentness bitmask
- for (unsigned int b = 0; b<nMaskSize; b++) {
- unsigned char chAvail = 0;
- for (unsigned int i = 0; i < 8 && 2+b*8+i < vout.size(); i++)
- if (!vout[2+b*8+i].IsNull())
- chAvail |= (1 << i);
- ::Serialize(s, chAvail);
- }
- // txouts themself
- for (unsigned int i = 0; i < vout.size(); i++) {
- if (!vout[i].IsNull())
- ::Serialize(s, CTxOutCompressor(REF(vout[i])));
- }
- // coinbase height
- ::Serialize(s, VARINT(nHeight));
+ assert(!IsSpent());
+ uint32_t code = nHeight * 2 + fCoinBase;
+ ::Serialize(s, VARINT(code));
+ ::Serialize(s, CTxOutCompressor(REF(out)));
}
template<typename Stream>
void Unserialize(Stream &s) {
- unsigned int nCode = 0;
- // version
- ::Unserialize(s, VARINT(this->nVersion));
- // header code
- ::Unserialize(s, VARINT(nCode));
- fCoinBase = nCode & 1;
- std::vector<bool> vAvail(2, false);
- vAvail[0] = (nCode & 2) != 0;
- vAvail[1] = (nCode & 4) != 0;
- unsigned int nMaskCode = (nCode / 8) + ((nCode & 6) != 0 ? 0 : 1);
- // spentness bitmask
- while (nMaskCode > 0) {
- unsigned char chAvail = 0;
- ::Unserialize(s, chAvail);
- for (unsigned int p = 0; p < 8; p++) {
- bool f = (chAvail & (1 << p)) != 0;
- vAvail.push_back(f);
- }
- if (chAvail != 0)
- nMaskCode--;
- }
- // txouts themself
- vout.assign(vAvail.size(), CTxOut());
- for (unsigned int i = 0; i < vAvail.size(); i++) {
- if (vAvail[i])
- ::Unserialize(s, REF(CTxOutCompressor(vout[i])));
- }
- // coinbase height
- ::Unserialize(s, VARINT(nHeight));
- Cleanup();
+ uint32_t code = 0;
+ ::Unserialize(s, VARINT(code));
+ nHeight = code >> 1;
+ fCoinBase = code & 1;
+ ::Unserialize(s, REF(CTxOutCompressor(out)));
}
- //! mark a vout spent
- bool Spend(uint32_t nPos);
-
- //! check whether a particular output is still available
- bool IsAvailable(unsigned int nPos) const {
- return (nPos < vout.size() && !vout[nPos].IsNull());
- }
-
- //! check whether the entire CCoins is spent
- //! note that only !IsPruned() CCoins can be serialized
- bool IsPruned() const {
- BOOST_FOREACH(const CTxOut &out, vout)
- if (!out.IsNull())
- return false;
- return true;
+ bool IsSpent() const {
+ return out.IsNull();
}
size_t DynamicMemoryUsage() const {
- size_t ret = memusage::DynamicUsage(vout);
- BOOST_FOREACH(const CTxOut &out, vout) {
- ret += RecursiveDynamicUsage(out.scriptPubKey);
- }
- return ret;
+ return memusage::DynamicUsage(out.scriptPubKey);
}
};
-class SaltedTxidHasher
+class SaltedOutpointHasher
{
private:
/** Salt */
const uint64_t k0, k1;
public:
- SaltedTxidHasher();
+ SaltedOutpointHasher();
/**
* This *must* return size_t. With Boost 1.46 on 32-bit systems the
* unordered_map will behave unpredictably if the custom hasher returns a
* uint64_t, resulting in failures when syncing the chain (#4634).
*/
- size_t operator()(const uint256& txid) const {
- return SipHashUint256(k0, k1, txid);
+ size_t operator()(const COutPoint& id) const {
+ return SipHashUint256Extra(k0, k1, id.hash, id.n);
}
};
struct CCoinsCacheEntry
{
- CCoins coins; // The actual cached data.
+ Coin coin; // The actual cached data.
unsigned char flags;
enum Flags {
@@ -276,21 +115,21 @@ struct CCoinsCacheEntry
*/
};
- CCoinsCacheEntry() : coins(), flags(0) {}
+ CCoinsCacheEntry() : flags(0) {}
+ explicit CCoinsCacheEntry(Coin&& coin_) : coin(std::move(coin_)), flags(0) {}
};
-typedef boost::unordered_map<uint256, CCoinsCacheEntry, SaltedTxidHasher> CCoinsMap;
+typedef std::unordered_map<COutPoint, CCoinsCacheEntry, SaltedOutpointHasher> CCoinsMap;
/** Cursor for iterating over CoinsView state */
class CCoinsViewCursor
{
public:
CCoinsViewCursor(const uint256 &hashBlockIn): hashBlock(hashBlockIn) {}
- virtual ~CCoinsViewCursor();
+ virtual ~CCoinsViewCursor() {}
- virtual bool GetKey(uint256 &key) const = 0;
- virtual bool GetValue(CCoins &coins) const = 0;
- /* Don't care about GetKeySize here */
+ virtual bool GetKey(COutPoint &key) const = 0;
+ virtual bool GetValue(Coin &coin) const = 0;
virtual unsigned int GetValueSize() const = 0;
virtual bool Valid() const = 0;
@@ -306,17 +145,25 @@ private:
class CCoinsView
{
public:
- //! Retrieve the CCoins (unspent transaction outputs) for a given txid
- virtual bool GetCoins(const uint256 &txid, CCoins &coins) const;
+ /** Retrieve the Coin (unspent transaction output) for a given outpoint.
+ * Returns true only when an unspent coin was found, which is returned in coin.
+ * When false is returned, coin's value is unspecified.
+ */
+ virtual bool GetCoin(const COutPoint &outpoint, Coin &coin) const;
- //! Just check whether we have data for a given txid.
- //! This may (but cannot always) return true for fully spent transactions
- virtual bool HaveCoins(const uint256 &txid) const;
+ //! Just check whether a given outpoint is unspent.
+ virtual bool HaveCoin(const COutPoint &outpoint) const;
//! Retrieve the block hash whose state this CCoinsView currently represents
virtual uint256 GetBestBlock() const;
- //! Do a bulk modification (multiple CCoins changes + BestBlock change).
+ //! Retrieve the range of blocks that may have been only partially written.
+ //! If the database is in a consistent state, the result is the empty vector.
+ //! Otherwise, a two-element vector is returned consisting of the new and
+ //! the old block hash, in that order.
+ virtual std::vector<uint256> GetHeadBlocks() const;
+
+ //! Do a bulk modification (multiple Coin changes + BestBlock change).
//! The passed mapCoins can be modified.
virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
@@ -325,6 +172,9 @@ public:
//! As we use CCoinsViews polymorphically, have a virtual destructor
virtual ~CCoinsView() {}
+
+ //! Estimate database size (0 if not implemented)
+ virtual size_t EstimateSize() const { return 0; }
};
@@ -336,45 +186,21 @@ protected:
public:
CCoinsViewBacked(CCoinsView *viewIn);
- bool GetCoins(const uint256 &txid, CCoins &coins) const;
- bool HaveCoins(const uint256 &txid) const;
- uint256 GetBestBlock() const;
+ bool GetCoin(const COutPoint &outpoint, Coin &coin) const override;
+ bool HaveCoin(const COutPoint &outpoint) const override;
+ uint256 GetBestBlock() const override;
+ std::vector<uint256> GetHeadBlocks() const override;
void SetBackend(CCoinsView &viewIn);
- bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
- CCoinsViewCursor *Cursor() const;
+ bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override;
+ CCoinsViewCursor *Cursor() const override;
+ size_t EstimateSize() const override;
};
-class CCoinsViewCache;
-
-/**
- * A reference to a mutable cache entry. Encapsulating it allows us to run
- * cleanup code after the modification is finished, and keeping track of
- * concurrent modifications.
- */
-class CCoinsModifier
-{
-private:
- 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; }
- CCoins& operator*() { return it->second.coins; }
- ~CCoinsModifier();
- friend class CCoinsViewCache;
-};
-
/** CCoinsView that adds a memory cache for transactions to another CCoinsView */
class CCoinsViewCache : public CCoinsViewBacked
{
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".
@@ -382,51 +208,58 @@ protected:
mutable uint256 hashBlock;
mutable CCoinsMap cacheCoins;
- /* Cached dynamic memory usage for the inner CCoins objects. */
+ /* Cached dynamic memory usage for the inner Coin objects. */
mutable size_t cachedCoinsUsage;
public:
CCoinsViewCache(CCoinsView *baseIn);
- ~CCoinsViewCache();
+
+ /**
+ * By deleting the copy constructor, we prevent accidentally using it when one intends to create a cache on top of a base cache.
+ */
+ CCoinsViewCache(const CCoinsViewCache &) = delete;
// Standard CCoinsView methods
- bool GetCoins(const uint256 &txid, CCoins &coins) const;
- bool HaveCoins(const uint256 &txid) const;
- uint256 GetBestBlock() const;
+ bool GetCoin(const COutPoint &outpoint, Coin &coin) const override;
+ bool HaveCoin(const COutPoint &outpoint) const override;
+ uint256 GetBestBlock() const override;
void SetBestBlock(const uint256 &hashBlock);
- bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
+ bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override;
+ CCoinsViewCursor* Cursor() const override {
+ throw std::logic_error("CCoinsViewCache cursor iteration not supported.");
+ }
/**
- * Check if we have the given tx already loaded in this cache.
- * The semantics are the same as HaveCoins(), but no calls to
+ * Check if we have the given utxo already loaded in this cache.
+ * The semantics are the same as HaveCoin(), but no calls to
* the backing CCoinsView are made.
*/
- bool HaveCoinsInCache(const uint256 &txid) const;
+ bool HaveCoinInCache(const COutPoint &outpoint) const;
/**
- * Return a pointer to CCoins in the cache, or NULL if not found. This is
- * more efficient than GetCoins. Modifications to other cache entries are
- * allowed while accessing the returned pointer.
+ * Return a reference to Coin in the cache, or a pruned one if not found. This is
+ * more efficient than GetCoin.
+ *
+ * Generally, do not hold the reference returned for more than a short scope.
+ * While the current implementation allows for modifications to the contents
+ * of the cache while holding the reference, this behavior should not be relied
+ * on! To be safe, best to not hold the returned reference through any other
+ * calls to this cache.
*/
- const CCoins* AccessCoins(const uint256 &txid) const;
+ const Coin& AccessCoin(const COutPoint &output) const;
/**
- * Return a modifiable reference to a CCoins. If no entry with the given
- * txid exists, a new one is created. Simultaneous modifications are not
- * allowed.
+ * Add a coin. Set potential_overwrite to true if a non-pruned version may
+ * already exist.
*/
- CCoinsModifier ModifyCoins(const uint256 &txid);
+ void AddCoin(const COutPoint& outpoint, Coin&& coin, bool potential_overwrite);
/**
- * Return a modifiable reference to a CCoins. Assumes that no entry with the given
- * txid exists and creates a new one. This saves a database access in the case where
- * the coins were to be wiped out by FromTx anyway. This should not be called with
- * the 2 historical coinbase duplicate pairs because the new coins are marked fresh, and
- * in the event the duplicate coinbase was spent before a flush, the now pruned coins
- * would not properly overwrite the first coinbase of the pair. Simultaneous modifications
- * are not allowed.
+ * Spend a coin. Pass moveto in order to get the deleted data.
+ * If no unspent output exists for the passed outpoint, this call
+ * has no effect.
*/
- CCoinsModifier ModifyNewCoins(const uint256 &txid, bool coinbase);
+ bool SpendCoin(const COutPoint &outpoint, Coin* moveto = nullptr);
/**
* Push the modifications applied to this cache to its base.
@@ -436,12 +269,12 @@ public:
bool Flush();
/**
- * Removes the transaction with the given hash from the cache, if it is
+ * Removes the UTXO with the given outpoint from the cache, if it is
* not modified.
*/
- void Uncache(const uint256 &txid);
+ void Uncache(const COutPoint &outpoint);
- //! Calculate the size of the cache (in number of transactions)
+ //! Calculate the size of the cache (in number of transaction outputs)
unsigned int GetCacheSize() const;
//! Calculate the size of the cache (in bytes)
@@ -460,24 +293,22 @@ public:
//! Check whether all prevouts of the transaction are present in the UTXO set represented by this view
bool HaveInputs(const CTransaction& tx) const;
- /**
- * Return priority of tx at height nHeight. Also calculate the sum of the values of the inputs
- * that are already in the chain. These are the inputs that will age and increase priority as
- * new blocks are added to the chain.
- */
- double GetPriority(const CTransaction &tx, int nHeight, CAmount &inChainInputValue) const;
-
- const CTxOut &GetOutputFor(const CTxIn& input) const;
-
- friend class CCoinsModifier;
-
private:
- CCoinsMap::const_iterator FetchCoins(const uint256 &txid) const;
-
- /**
- * By making the copy constructor private, we prevent accidentally using it when one intends to create a cache on top of a base cache.
- */
- CCoinsViewCache(const CCoinsViewCache &);
+ CCoinsMap::iterator FetchCoin(const COutPoint &outpoint) const;
};
+//! Utility function to add all of a transaction's outputs to a cache.
+// When check is false, this assumes that overwrites are only possible for coinbase transactions.
+// When check is true, the underlying view may be queried to determine whether an addition is
+// an overwrite.
+// TODO: pass in a boolean to limit these possible overwrites to known
+// (pre-BIP34) cases.
+void AddCoins(CCoinsViewCache& cache, const CTransaction& tx, int nHeight, bool check = false);
+
+//! Utility function to find any unspent output with a given txid.
+// This function can be quite expensive because in the event of a transaction
+// which is not found in the cache, it can cause up to MAX_OUTPUTS_PER_BLOCK
+// lookups to database, so it should be used with care.
+const Coin& AccessByTxid(const CCoinsViewCache& cache, const uint256& txid);
+
#endif // BITCOIN_COINS_H
diff --git a/src/compat.h b/src/compat.h
index 28aa77eea2..e022659c01 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -47,10 +47,8 @@
#include <unistd.h>
#endif
-#ifdef WIN32
-#define MSG_DONTWAIT 0
-#else
-typedef u_int SOCKET;
+#ifndef WIN32
+typedef unsigned int SOCKET;
#include "errno.h"
#define WSAGetLastError() errno
#define WSAEINVAL EINVAL
@@ -74,16 +72,11 @@ typedef u_int SOCKET;
#define MAX_PATH 1024
#endif
-// As Solaris does not have the MSG_NOSIGNAL flag for send(2) syscall, it is defined as 0
-#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
-#define MSG_NOSIGNAL 0
-#endif
-
#if HAVE_DECL_STRNLEN == 0
size_t strnlen( const char *start, size_t max_len);
#endif // HAVE_DECL_STRNLEN
-bool static inline IsSelectableSocket(SOCKET s) {
+bool static inline IsSelectableSocket(const SOCKET& s) {
#ifdef WIN32
return true;
#else
diff --git a/src/compat/byteswap.h b/src/compat/byteswap.h
index 3c5a5c0837..d93ff7413a 100644
--- a/src/compat/byteswap.h
+++ b/src/compat/byteswap.h
@@ -35,7 +35,7 @@
#if HAVE_DECL_BSWAP_16 == 0
inline uint16_t bswap_16(uint16_t x)
{
- return (x >> 8) | ((x & 0x00ff) << 8);
+ return (x >> 8) | (x << 8);
}
#endif // HAVE_DECL_BSWAP16
diff --git a/src/compat/endian.h b/src/compat/endian.h
index 79d6b2fdbb..dbf178f53c 100644
--- a/src/compat/endian.h
+++ b/src/compat/endian.h
@@ -9,10 +9,10 @@
#include "config/bitcoin-config.h"
#endif
-#include <stdint.h>
-
#include "compat/byteswap.h"
+#include <stdint.h>
+
#if defined(HAVE_ENDIAN_H)
#include <endian.h>
#elif defined(HAVE_SYS_ENDIAN_H)
diff --git a/src/compat/glibc_sanity.cpp b/src/compat/glibc_sanity.cpp
index d62d74d462..b4d1c90992 100644
--- a/src/compat/glibc_sanity.cpp
+++ b/src/compat/glibc_sanity.cpp
@@ -56,7 +56,7 @@ bool sanity_test_fdelt()
}
#endif
-} // anon namespace
+} // namespace
bool glibc_sanity_test()
{
diff --git a/src/compat/glibcxx_sanity.cpp b/src/compat/glibcxx_sanity.cpp
index cee8a98c7f..569fb1bbe8 100644
--- a/src/compat/glibcxx_sanity.cpp
+++ b/src/compat/glibcxx_sanity.cpp
@@ -38,7 +38,7 @@ bool sanity_test_list(unsigned int size)
return true;
}
-} // anon namespace
+} // namespace
// trigger: string::at(x) on an empty string to trigger __throw_out_of_range_fmt.
// test: force std::string to throw an out_of_range exception. Verify that
diff --git a/src/compressor.cpp b/src/compressor.cpp
index 20c154fc1e..f4c12f38d2 100644
--- a/src/compressor.cpp
+++ b/src/compressor.cpp
@@ -93,7 +93,7 @@ bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector<unsigne
script[0] = OP_DUP;
script[1] = OP_HASH160;
script[2] = 20;
- memcpy(&script[3], &in[0], 20);
+ memcpy(&script[3], in.data(), 20);
script[23] = OP_EQUALVERIFY;
script[24] = OP_CHECKSIG;
return true;
@@ -101,7 +101,7 @@ bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector<unsigne
script.resize(23);
script[0] = OP_HASH160;
script[1] = 20;
- memcpy(&script[2], &in[0], 20);
+ memcpy(&script[2], in.data(), 20);
script[22] = OP_EQUAL;
return true;
case 0x02:
@@ -109,14 +109,14 @@ bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector<unsigne
script.resize(35);
script[0] = 33;
script[1] = nSize;
- memcpy(&script[2], &in[0], 32);
+ memcpy(&script[2], in.data(), 32);
script[34] = OP_CHECKSIG;
return true;
case 0x04:
case 0x05:
unsigned char vch[33] = {};
vch[0] = nSize - 2;
- memcpy(&vch[1], &in[0], 32);
+ memcpy(&vch[1], in.data(), 32);
CPubKey pubkey(&vch[0], &vch[33]);
if (!pubkey.Decompress())
return false;
diff --git a/src/compressor.h b/src/compressor.h
index 015911484a..094c1bcfe1 100644
--- a/src/compressor.h
+++ b/src/compressor.h
@@ -53,7 +53,7 @@ protected:
unsigned int GetSpecialSize(unsigned int nSize) const;
bool Decompress(unsigned int nSize, const std::vector<unsigned char> &out);
public:
- CScriptCompressor(CScript &scriptIn) : script(scriptIn) { }
+ explicit CScriptCompressor(CScript &scriptIn) : script(scriptIn) { }
template<typename Stream>
void Serialize(Stream &s) const {
@@ -99,7 +99,7 @@ public:
static uint64_t CompressAmount(uint64_t nAmount);
static uint64_t DecompressAmount(uint64_t nAmount);
- CTxOutCompressor(CTxOut &txoutIn) : txout(txoutIn) { }
+ explicit CTxOutCompressor(CTxOut &txoutIn) : txout(txoutIn) { }
ADD_SERIALIZE_METHODS;
diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h
index 351911a3a4..ddd4ee9fab 100644
--- a/src/consensus/consensus.h
+++ b/src/consensus/consensus.h
@@ -6,19 +6,23 @@
#ifndef BITCOIN_CONSENSUS_CONSENSUS_H
#define BITCOIN_CONSENSUS_CONSENSUS_H
+#include <stdlib.h>
#include <stdint.h>
/** The maximum allowed size for a serialized block, in bytes (only for buffer size limits) */
static const unsigned int MAX_BLOCK_SERIALIZED_SIZE = 4000000;
/** The maximum allowed weight for a block, see BIP 141 (network rule) */
static const unsigned int MAX_BLOCK_WEIGHT = 4000000;
-/** The maximum allowed size for a block excluding witness data, in bytes (network rule) */
-static const unsigned int MAX_BLOCK_BASE_SIZE = 1000000;
/** The maximum allowed number of signature check operations in a block (network rule) */
static const int64_t MAX_BLOCK_SIGOPS_COST = 80000;
/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */
static const int COINBASE_MATURITY = 100;
+static const int WITNESS_SCALE_FACTOR = 4;
+
+static const size_t MIN_TRANSACTION_WEIGHT = WITNESS_SCALE_FACTOR * 60; // 60 is the lower bound for the size of a valid serialized CTransaction
+static const size_t MIN_SERIALIZABLE_TRANSACTION_WEIGHT = WITNESS_SCALE_FACTOR * 10; // 10 is the lower bound for the size of a serialized CTransaction
+
/** Flags for nSequence and nLockTime locks */
enum {
/* Interpret sequence numbers as relative lock-time constraints. */
diff --git a/src/consensus/merkle.cpp b/src/consensus/merkle.cpp
index 1ce5a9d87e..798ce4b5fd 100644
--- a/src/consensus/merkle.cpp
+++ b/src/consensus/merkle.cpp
@@ -132,13 +132,13 @@ static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot
uint256 ComputeMerkleRoot(const std::vector<uint256>& leaves, bool* mutated) {
uint256 hash;
- MerkleComputation(leaves, &hash, mutated, -1, NULL);
+ MerkleComputation(leaves, &hash, mutated, -1, nullptr);
return hash;
}
std::vector<uint256> ComputeMerkleBranch(const std::vector<uint256>& leaves, uint32_t position) {
std::vector<uint256> ret;
- MerkleComputation(leaves, NULL, NULL, position, &ret);
+ MerkleComputation(leaves, nullptr, nullptr, position, &ret);
return ret;
}
diff --git a/src/consensus/merkle.h b/src/consensus/merkle.h
index 194aea9b75..33764c7460 100644
--- a/src/consensus/merkle.h
+++ b/src/consensus/merkle.h
@@ -12,7 +12,7 @@
#include "primitives/block.h"
#include "uint256.h"
-uint256 ComputeMerkleRoot(const std::vector<uint256>& leaves, bool* mutated = NULL);
+uint256 ComputeMerkleRoot(const std::vector<uint256>& leaves, bool* mutated = nullptr);
std::vector<uint256> ComputeMerkleBranch(const std::vector<uint256>& leaves, uint32_t position);
uint256 ComputeMerkleRootFromBranch(const uint256& leaf, const std::vector<uint256>& branch, uint32_t position);
@@ -20,13 +20,13 @@ uint256 ComputeMerkleRootFromBranch(const uint256& leaf, const std::vector<uint2
* Compute the Merkle root of the transactions in a block.
* *mutated is set to true if a duplicated subtree was found.
*/
-uint256 BlockMerkleRoot(const CBlock& block, bool* mutated = NULL);
+uint256 BlockMerkleRoot(const CBlock& block, bool* mutated = nullptr);
/*
* Compute the Merkle root of the witness transactions in a block.
* *mutated is set to true if a duplicated subtree was found.
*/
-uint256 BlockWitnessMerkleRoot(const CBlock& block, bool* mutated = NULL);
+uint256 BlockWitnessMerkleRoot(const CBlock& block, bool* mutated = nullptr);
/*
* Compute the Merkle branch for the tree of transactions in a block, for a
diff --git a/src/consensus/params.h b/src/consensus/params.h
index 3f98938f7e..6240e82857 100644
--- a/src/consensus/params.h
+++ b/src/consensus/params.h
@@ -47,7 +47,7 @@ struct Params {
/** Block height at which BIP66 becomes active */
int BIP66Height;
/**
- * Minimum blocks including miner confirmation of the total of 2016 blocks in a retargetting period,
+ * Minimum blocks including miner confirmation of the total of 2016 blocks in a retargeting period,
* (nPowTargetTimespan / nPowTargetSpacing) which is also used for BIP9 deployments.
* Examples: 1916 for 95%, 1512 for testchains.
*/
diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp
new file mode 100644
index 0000000000..0a71915d1d
--- /dev/null
+++ b/src/consensus/tx_verify.cpp
@@ -0,0 +1,250 @@
+// Copyright (c) 2017-2017 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 "tx_verify.h"
+
+#include "consensus.h"
+#include "primitives/transaction.h"
+#include "script/interpreter.h"
+#include "validation.h"
+
+// TODO remove the following dependencies
+#include "chain.h"
+#include "coins.h"
+#include "utilmoneystr.h"
+
+bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
+{
+ if (tx.nLockTime == 0)
+ return true;
+ if ((int64_t)tx.nLockTime < ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime))
+ return true;
+ for (const auto& txin : tx.vin) {
+ if (!(txin.nSequence == CTxIn::SEQUENCE_FINAL))
+ return false;
+ }
+ return true;
+}
+
+std::pair<int, int64_t> CalculateSequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeights, const CBlockIndex& block)
+{
+ assert(prevHeights->size() == tx.vin.size());
+
+ // Will be set to the equivalent height- and time-based nLockTime
+ // values that would be necessary to satisfy all relative lock-
+ // time constraints given our view of block chain history.
+ // The semantics of nLockTime are the last invalid height/time, so
+ // use -1 to have the effect of any height or time being valid.
+ int nMinHeight = -1;
+ int64_t nMinTime = -1;
+
+ // tx.nVersion is signed integer so requires cast to unsigned otherwise
+ // we would be doing a signed comparison and half the range of nVersion
+ // wouldn't support BIP 68.
+ bool fEnforceBIP68 = static_cast<uint32_t>(tx.nVersion) >= 2
+ && flags & LOCKTIME_VERIFY_SEQUENCE;
+
+ // Do not enforce sequence numbers as a relative lock time
+ // unless we have been instructed to
+ if (!fEnforceBIP68) {
+ return std::make_pair(nMinHeight, nMinTime);
+ }
+
+ for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
+ const CTxIn& txin = tx.vin[txinIndex];
+
+ // Sequence numbers with the most significant bit set are not
+ // treated as relative lock-times, nor are they given any
+ // consensus-enforced meaning at this point.
+ if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) {
+ // The height of this input is not relevant for sequence locks
+ (*prevHeights)[txinIndex] = 0;
+ continue;
+ }
+
+ int nCoinHeight = (*prevHeights)[txinIndex];
+
+ if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) {
+ int64_t nCoinTime = block.GetAncestor(std::max(nCoinHeight-1, 0))->GetMedianTimePast();
+ // NOTE: Subtract 1 to maintain nLockTime semantics
+ // BIP 68 relative lock times have the semantics of calculating
+ // the first block or time at which the transaction would be
+ // valid. When calculating the effective block time or height
+ // for the entire transaction, we switch to using the
+ // semantics of nLockTime which is the last invalid block
+ // time or height. Thus we subtract 1 from the calculated
+ // time or height.
+
+ // Time-based relative lock-times are measured from the
+ // smallest allowed timestamp of the block containing the
+ // txout being spent, which is the median time past of the
+ // block prior.
+ nMinTime = std::max(nMinTime, nCoinTime + (int64_t)((txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) << CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) - 1);
+ } else {
+ nMinHeight = std::max(nMinHeight, nCoinHeight + (int)(txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) - 1);
+ }
+ }
+
+ return std::make_pair(nMinHeight, nMinTime);
+}
+
+bool EvaluateSequenceLocks(const CBlockIndex& block, std::pair<int, int64_t> lockPair)
+{
+ assert(block.pprev);
+ int64_t nBlockTime = block.pprev->GetMedianTimePast();
+ if (lockPair.first >= block.nHeight || lockPair.second >= nBlockTime)
+ return false;
+
+ return true;
+}
+
+bool SequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeights, const CBlockIndex& block)
+{
+ return EvaluateSequenceLocks(block, CalculateSequenceLocks(tx, flags, prevHeights, block));
+}
+
+unsigned int GetLegacySigOpCount(const CTransaction& tx)
+{
+ unsigned int nSigOps = 0;
+ for (const auto& txin : tx.vin)
+ {
+ nSigOps += txin.scriptSig.GetSigOpCount(false);
+ }
+ for (const auto& txout : tx.vout)
+ {
+ nSigOps += txout.scriptPubKey.GetSigOpCount(false);
+ }
+ return nSigOps;
+}
+
+unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs)
+{
+ if (tx.IsCoinBase())
+ return 0;
+
+ unsigned int nSigOps = 0;
+ for (unsigned int i = 0; i < tx.vin.size(); i++)
+ {
+ const Coin& coin = inputs.AccessCoin(tx.vin[i].prevout);
+ assert(!coin.IsSpent());
+ const CTxOut &prevout = coin.out;
+ if (prevout.scriptPubKey.IsPayToScriptHash())
+ nSigOps += prevout.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig);
+ }
+ return nSigOps;
+}
+
+int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, int flags)
+{
+ int64_t nSigOps = GetLegacySigOpCount(tx) * WITNESS_SCALE_FACTOR;
+
+ if (tx.IsCoinBase())
+ return nSigOps;
+
+ if (flags & SCRIPT_VERIFY_P2SH) {
+ nSigOps += GetP2SHSigOpCount(tx, inputs) * WITNESS_SCALE_FACTOR;
+ }
+
+ for (unsigned int i = 0; i < tx.vin.size(); i++)
+ {
+ const Coin& coin = inputs.AccessCoin(tx.vin[i].prevout);
+ assert(!coin.IsSpent());
+ const CTxOut &prevout = coin.out;
+ nSigOps += CountWitnessSigOps(tx.vin[i].scriptSig, prevout.scriptPubKey, &tx.vin[i].scriptWitness, flags);
+ }
+ return nSigOps;
+}
+
+bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fCheckDuplicateInputs)
+{
+ // Basic checks that don't depend on any context
+ if (tx.vin.empty())
+ return state.DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty");
+ if (tx.vout.empty())
+ return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty");
+ // Size limits (this doesn't take the witness into account, as that hasn't been checked for malleability)
+ if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT)
+ return state.DoS(100, false, REJECT_INVALID, "bad-txns-oversize");
+
+ // Check for negative or overflow output values
+ CAmount nValueOut = 0;
+ for (const auto& txout : tx.vout)
+ {
+ if (txout.nValue < 0)
+ return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-negative");
+ if (txout.nValue > MAX_MONEY)
+ return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-toolarge");
+ nValueOut += txout.nValue;
+ if (!MoneyRange(nValueOut))
+ return state.DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge");
+ }
+
+ // Check for duplicate inputs - note that this check is slow so we skip it in CheckBlock
+ if (fCheckDuplicateInputs) {
+ std::set<COutPoint> vInOutPoints;
+ for (const auto& txin : tx.vin)
+ {
+ if (!vInOutPoints.insert(txin.prevout).second)
+ return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-duplicate");
+ }
+ }
+
+ if (tx.IsCoinBase())
+ {
+ if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100)
+ return state.DoS(100, false, REJECT_INVALID, "bad-cb-length");
+ }
+ else
+ {
+ for (const auto& txin : tx.vin)
+ if (txin.prevout.IsNull())
+ return state.DoS(10, false, REJECT_INVALID, "bad-txns-prevout-null");
+ }
+
+ return true;
+}
+
+bool Consensus::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(false, 0, "", "Inputs unavailable");
+
+ CAmount nValueIn = 0;
+ CAmount nFees = 0;
+ for (unsigned int i = 0; i < tx.vin.size(); i++)
+ {
+ const COutPoint &prevout = tx.vin[i].prevout;
+ const Coin& coin = inputs.AccessCoin(prevout);
+ assert(!coin.IsSpent());
+
+ // If prev is coinbase, check that it's matured
+ if (coin.IsCoinBase()) {
+ if (nSpendHeight - coin.nHeight < COINBASE_MATURITY)
+ return state.Invalid(false,
+ REJECT_INVALID, "bad-txns-premature-spend-of-coinbase",
+ strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight));
+ }
+
+ // Check for negative or overflow input values
+ nValueIn += coin.out.nValue;
+ if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn))
+ return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange");
+
+ }
+
+ if (nValueIn < tx.GetValueOut())
+ 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, false, REJECT_INVALID, "bad-txns-fee-negative");
+ nFees += nTxFee;
+ if (!MoneyRange(nFees))
+ return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-outofrange");
+ return true;
+}
diff --git a/src/consensus/tx_verify.h b/src/consensus/tx_verify.h
new file mode 100644
index 0000000000..d46d3294ca
--- /dev/null
+++ b/src/consensus/tx_verify.h
@@ -0,0 +1,78 @@
+// Copyright (c) 2017-2017 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_TX_VERIFY_H
+#define BITCOIN_CONSENSUS_TX_VERIFY_H
+
+#include <stdint.h>
+#include <vector>
+
+class CBlockIndex;
+class CCoinsViewCache;
+class CTransaction;
+class CValidationState;
+
+/** Transaction validation functions */
+
+/** Context-independent validity checks */
+bool CheckTransaction(const CTransaction& tx, CValidationState& state, bool fCheckDuplicateInputs=true);
+
+namespace Consensus {
+/**
+ * Check whether all inputs of this transaction are valid (no double spends and amounts)
+ * This does not modify the UTXO set. This does not check scripts and sigs.
+ * Preconditions: tx.IsCoinBase() is false.
+ */
+bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight);
+} // namespace Consensus
+
+/** Auxiliary functions for transaction validation (ideally should not be exposed) */
+
+/**
+ * Count ECDSA signature operations the old-fashioned (pre-0.6) way
+ * @return number of sigops this transaction's outputs will produce when spent
+ * @see CTransaction::FetchInputs
+ */
+unsigned int GetLegacySigOpCount(const CTransaction& tx);
+
+/**
+ * Count ECDSA signature operations in pay-to-script-hash inputs.
+ *
+ * @param[in] mapInputs Map of previous transactions that have outputs we're spending
+ * @return maximum number of sigops required to validate this transaction's inputs
+ * @see CTransaction::FetchInputs
+ */
+unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& mapInputs);
+
+/**
+ * Compute total signature operation cost of a transaction.
+ * @param[in] tx Transaction for which we are computing the cost
+ * @param[in] inputs Map of previous transactions that have outputs we're spending
+ * @param[out] flags Script verification flags
+ * @return Total signature operation cost of tx
+ */
+int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, int flags);
+
+/**
+ * Check if transaction is final and can be included in a block with the
+ * specified height and time. Consensus critical.
+ */
+bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime);
+
+/**
+ * Calculates the block height and previous block's median time past at
+ * which the transaction will be considered final in the context of BIP 68.
+ * Also removes from the vector of input heights any entries which did not
+ * correspond to sequence locked inputs as they do not affect the calculation.
+ */
+std::pair<int, int64_t> CalculateSequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeights, const CBlockIndex& block);
+
+bool EvaluateSequenceLocks(const CBlockIndex& block, std::pair<int, int64_t> lockPair);
+/**
+ * Check if transaction is final per BIP 68 sequence numbers and can be included in a block.
+ * Consensus critical. Takes as input a list of heights at which tx's inputs (in order) confirmed.
+ */
+bool SequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeights, const CBlockIndex& block);
+
+#endif // BITCOIN_CONSENSUS_TX_VERIFY_H
diff --git a/src/consensus/validation.h b/src/consensus/validation.h
index 5a7d7f11a9..b6740c9d9f 100644
--- a/src/consensus/validation.h
+++ b/src/consensus/validation.h
@@ -7,6 +7,10 @@
#define BITCOIN_CONSENSUS_VALIDATION_H
#include <string>
+#include "version.h"
+#include "consensus/consensus.h"
+#include "primitives/transaction.h"
+#include "primitives/block.h"
/** "reject" message codes */
static const unsigned char REJECT_MALFORMED = 0x01;
@@ -14,7 +18,7 @@ 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_DUST = 0x41; // part of BIP 61
static const unsigned char REJECT_INSUFFICIENTFEE = 0x42;
static const unsigned char REJECT_CHECKPOINT = 0x43;
@@ -85,4 +89,17 @@ public:
std::string GetDebugMessage() const { return strDebugMessage; }
};
+// These implement the weight = (stripped_size * 4) + witness_size formula,
+// using only serialization with and without witness data. As witness_size
+// is equal to total_size - stripped_size, this formula is identical to:
+// weight = (stripped_size * 3) + total_size.
+static inline int64_t GetTransactionWeight(const CTransaction& tx)
+{
+ return ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
+}
+static inline int64_t GetBlockWeight(const CBlock& block)
+{
+ return ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION);
+}
+
#endif // BITCOIN_CONSENSUS_VALIDATION_H
diff --git a/src/core_io.h b/src/core_io.h
index 2d63be5fc4..ccc72ebb32 100644
--- a/src/core_io.h
+++ b/src/core_io.h
@@ -5,6 +5,8 @@
#ifndef BITCOIN_CORE_IO_H
#define BITCOIN_CORE_IO_H
+#include "amount.h"
+
#include <string>
#include <vector>
@@ -25,9 +27,10 @@ uint256 ParseHashStr(const std::string&, const std::string& strName);
std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName);
// core_write.cpp
+UniValue ValueFromAmount(const CAmount& amount);
std::string FormatScript(const CScript& script);
std::string EncodeHexTx(const CTransaction& tx, const int serializeFlags = 0);
void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
-void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry);
+void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex = true, int serialize_flags = 0);
#endif // BITCOIN_CORE_IO_H
diff --git a/src/core_memusage.h b/src/core_memusage.h
index 5e10182075..f038e7b154 100644
--- a/src/core_memusage.h
+++ b/src/core_memusage.h
@@ -10,7 +10,7 @@
#include "memusage.h"
static inline size_t RecursiveDynamicUsage(const CScript& script) {
- return memusage::DynamicUsage(*static_cast<const CScriptBase*>(&script));
+ return memusage::DynamicUsage(script);
}
static inline size_t RecursiveDynamicUsage(const COutPoint& out) {
@@ -63,4 +63,9 @@ static inline size_t RecursiveDynamicUsage(const CBlockLocator& locator) {
return memusage::DynamicUsage(locator.vHave);
}
+template<typename X>
+static inline size_t RecursiveDynamicUsage(const std::shared_ptr<X>& p) {
+ return p ? memusage::DynamicUsage(p) + RecursiveDynamicUsage(*p) : 0;
+}
+
#endif // BITCOIN_CORE_MEMUSAGE_H
diff --git a/src/core_read.cpp b/src/core_read.cpp
index 85bb62c176..7018131a13 100644
--- a/src/core_read.cpp
+++ b/src/core_read.cpp
@@ -18,19 +18,16 @@
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/split.hpp>
-#include <boost/assign/list_of.hpp>
-
-using namespace std;
CScript ParseScript(const std::string& s)
{
CScript result;
- static map<string, opcodetype> mapOpNames;
+ static std::map<std::string, opcodetype> mapOpNames;
if (mapOpNames.empty())
{
- for (int op = 0; op <= OP_NOP10; op++)
+ for (unsigned int op = 0; op <= MAX_OPCODE; op++)
{
// Allow OP_RESERVED to get into mapOpNames
if (op < OP_NOP && op != OP_RESERVED)
@@ -39,7 +36,7 @@ CScript ParseScript(const std::string& s)
const char* name = GetOpName((opcodetype)op);
if (strcmp(name, "OP_UNKNOWN") == 0)
continue;
- string strName(name);
+ std::string strName(name);
mapOpNames[strName] = (opcodetype)op;
// Convenience: OP_ADD and just ADD are both recognized:
boost::algorithm::replace_first(strName, "OP_", "");
@@ -47,7 +44,7 @@ CScript ParseScript(const std::string& s)
}
}
- vector<string> words;
+ std::vector<std::string> words;
boost::algorithm::split(words, s, boost::algorithm::is_any_of(" \t\n"), boost::algorithm::token_compress_on);
for (std::vector<std::string>::const_iterator w = words.begin(); w != words.end(); ++w)
@@ -57,16 +54,16 @@ CScript ParseScript(const std::string& s)
// Empty string, ignore. (boost::split given '' will return one word)
}
else if (all(*w, boost::algorithm::is_digit()) ||
- (boost::algorithm::starts_with(*w, "-") && all(string(w->begin()+1, w->end()), boost::algorithm::is_digit())))
+ (boost::algorithm::starts_with(*w, "-") && all(std::string(w->begin()+1, w->end()), boost::algorithm::is_digit())))
{
// Number
int64_t n = atoi64(*w);
result << n;
}
- else if (boost::algorithm::starts_with(*w, "0x") && (w->begin()+2 != w->end()) && IsHex(string(w->begin()+2, w->end())))
+ else if (boost::algorithm::starts_with(*w, "0x") && (w->begin()+2 != w->end()) && IsHex(std::string(w->begin()+2, w->end())))
{
// Raw hex data, inserted NOT pushed onto stack:
- std::vector<unsigned char> raw = ParseHex(string(w->begin()+2, w->end()));
+ std::vector<unsigned char> raw = ParseHex(std::string(w->begin()+2, w->end()));
result.insert(result.end(), raw.begin(), raw.end());
}
else if (w->size() >= 2 && boost::algorithm::starts_with(*w, "'") && boost::algorithm::ends_with(*w, "'"))
@@ -83,25 +80,47 @@ CScript ParseScript(const std::string& s)
}
else
{
- throw runtime_error("script parse error");
+ throw std::runtime_error("script parse error");
}
}
return result;
}
+// Check that all of the input and output scripts of a transaction contains valid opcodes
+bool CheckTxScriptsSanity(const CMutableTransaction& tx)
+{
+ // Check input scripts for non-coinbase txs
+ if (!CTransaction(tx).IsCoinBase()) {
+ for (unsigned int i = 0; i < tx.vin.size(); i++) {
+ if (!tx.vin[i].scriptSig.HasValidOps() || tx.vin[i].scriptSig.size() > MAX_SCRIPT_SIZE) {
+ return false;
+ }
+ }
+ }
+ // Check output scripts
+ for (unsigned int i = 0; i < tx.vout.size(); i++) {
+ if (!tx.vout[i].scriptPubKey.HasValidOps() || tx.vout[i].scriptPubKey.size() > MAX_SCRIPT_SIZE) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
bool DecodeHexTx(CMutableTransaction& tx, const std::string& strHexTx, bool fTryNoWitness)
{
- if (!IsHex(strHexTx))
+ if (!IsHex(strHexTx)) {
return false;
+ }
- vector<unsigned char> txData(ParseHex(strHexTx));
+ std::vector<unsigned char> txData(ParseHex(strHexTx));
if (fTryNoWitness) {
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
try {
ssData >> tx;
- if (ssData.eof()) {
+ if (ssData.eof() && CheckTxScriptsSanity(tx)) {
return true;
}
}
@@ -113,6 +132,9 @@ bool DecodeHexTx(CMutableTransaction& tx, const std::string& strHexTx, bool fTry
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
try {
ssData >> tx;
+ if (!ssData.empty()) {
+ return false;
+ }
}
catch (const std::exception&) {
return false;
@@ -138,9 +160,9 @@ bool DecodeHexBlk(CBlock& block, const std::string& strHexBlk)
return true;
}
-uint256 ParseHashUV(const UniValue& v, const string& strName)
+uint256 ParseHashUV(const UniValue& v, const std::string& strName)
{
- string strHex;
+ std::string strHex;
if (v.isStr())
strHex = v.getValStr();
return ParseHashStr(strHex, strName); // Note: ParseHashStr("") throws a runtime_error
@@ -149,19 +171,19 @@ uint256 ParseHashUV(const UniValue& v, const string& strName)
uint256 ParseHashStr(const std::string& strHex, const std::string& strName)
{
if (!IsHex(strHex)) // Note: IsHex("") is false
- throw runtime_error(strName+" must be hexadecimal string (not '"+strHex+"')");
+ throw std::runtime_error(strName + " must be hexadecimal string (not '" + strHex + "')");
uint256 result;
result.SetHex(strHex);
return result;
}
-vector<unsigned char> ParseHexUV(const UniValue& v, const string& strName)
+std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName)
{
- string strHex;
+ std::string strHex;
if (v.isStr())
strHex = v.getValStr();
if (!IsHex(strHex))
- throw runtime_error(strName+" must be hexadecimal string (not '"+strHex+"')");
+ throw std::runtime_error(strName + " must be hexadecimal string (not '" + strHex + "')");
return ParseHex(strHex);
}
diff --git a/src/core_write.cpp b/src/core_write.cpp
index ee8a897ca4..e16db13650 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -5,7 +5,8 @@
#include "core_io.h"
#include "base58.h"
-#include "primitives/transaction.h"
+#include "consensus/consensus.h"
+#include "consensus/validation.h"
#include "script/script.h"
#include "script/standard.h"
#include "serialize.h"
@@ -15,19 +16,24 @@
#include "utilmoneystr.h"
#include "utilstrencodings.h"
-#include <boost/assign/list_of.hpp>
-#include <boost/foreach.hpp>
-
-using namespace std;
+UniValue ValueFromAmount(const CAmount& amount)
+{
+ 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));
+}
-string FormatScript(const CScript& script)
+std::string FormatScript(const CScript& script)
{
- string ret;
+ std::string ret;
CScript::const_iterator it = script.begin();
opcodetype op;
while (it != script.end()) {
CScript::const_iterator it2 = it;
- vector<unsigned char> vch;
+ std::vector<unsigned char> vch;
if (script.GetOp2(it, op, &vch)) {
if (op == OP_0) {
ret += "0 ";
@@ -36,9 +42,9 @@ string FormatScript(const CScript& script)
ret += strprintf("%i ", op - OP_1NEGATE - 1);
continue;
} else if (op >= OP_NOP && op <= OP_NOP10) {
- string str(GetOpName(op));
- if (str.substr(0, 3) == string("OP_")) {
- ret += str.substr(3, string::npos) + " ";
+ std::string str(GetOpName(op));
+ if (str.substr(0, 3) == std::string("OP_")) {
+ ret += str.substr(3, std::string::npos) + " ";
continue;
}
}
@@ -55,15 +61,14 @@ string FormatScript(const CScript& script)
return ret.substr(0, ret.size() - 1);
}
-const map<unsigned char, string> mapSigHashTypes =
- boost::assign::map_list_of
- (static_cast<unsigned char>(SIGHASH_ALL), string("ALL"))
- (static_cast<unsigned char>(SIGHASH_ALL|SIGHASH_ANYONECANPAY), string("ALL|ANYONECANPAY"))
- (static_cast<unsigned char>(SIGHASH_NONE), string("NONE"))
- (static_cast<unsigned char>(SIGHASH_NONE|SIGHASH_ANYONECANPAY), string("NONE|ANYONECANPAY"))
- (static_cast<unsigned char>(SIGHASH_SINGLE), string("SINGLE"))
- (static_cast<unsigned char>(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY), string("SINGLE|ANYONECANPAY"))
- ;
+const std::map<unsigned char, std::string> mapSigHashTypes = {
+ {static_cast<unsigned char>(SIGHASH_ALL), std::string("ALL")},
+ {static_cast<unsigned char>(SIGHASH_ALL|SIGHASH_ANYONECANPAY), std::string("ALL|ANYONECANPAY")},
+ {static_cast<unsigned char>(SIGHASH_NONE), std::string("NONE")},
+ {static_cast<unsigned char>(SIGHASH_NONE|SIGHASH_ANYONECANPAY), std::string("NONE|ANYONECANPAY")},
+ {static_cast<unsigned char>(SIGHASH_SINGLE), std::string("SINGLE")},
+ {static_cast<unsigned char>(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY), std::string("SINGLE|ANYONECANPAY")},
+};
/**
* Create the assembly string representation of a CScript object.
@@ -72,11 +77,11 @@ const map<unsigned char, string> mapSigHashTypes =
* of a signature. Only pass true for scripts you believe could contain signatures. For example,
* pass false, or omit the this argument (defaults to false), for scriptPubKeys.
*/
-string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode)
+std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode)
{
- string str;
+ std::string str;
opcodetype opcode;
- vector<unsigned char> vch;
+ std::vector<unsigned char> vch;
CScript::const_iterator pc = script.begin();
while (pc < script.end()) {
if (!str.empty()) {
@@ -87,17 +92,17 @@ string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode)
return str;
}
if (0 <= opcode && opcode <= OP_PUSHDATA4) {
- if (vch.size() <= static_cast<vector<unsigned char>::size_type>(4)) {
+ if (vch.size() <= static_cast<std::vector<unsigned char>::size_type>(4)) {
str += strprintf("%d", CScriptNum(vch, false).getint());
} else {
// the IsUnspendable check makes sure not to try to decode OP_RETURN data that may match the format of a signature
if (fAttemptSighashDecode && !script.IsUnspendable()) {
- string strSigHashDecode;
+ std::string strSigHashDecode;
// goal: only attempt to decode a defined sighash type from data that looks like a signature within a scriptSig.
// this won't decode correctly formatted public keys in Pubkey or Multisig scripts due to
// the restrictions on the pubkey formats (see IsCompressedOrUncompressedPubKey) being incongruous with the
// checks in CheckSignatureEncoding.
- if (CheckSignatureEncoding(vch, SCRIPT_VERIFY_STRICTENC, NULL)) {
+ if (CheckSignatureEncoding(vch, SCRIPT_VERIFY_STRICTENC, nullptr)) {
const unsigned char chSigHashType = vch.back();
if (mapSigHashTypes.count(chSigHashType)) {
strSigHashDecode = "[" + mapSigHashTypes.find(chSigHashType)->second + "]";
@@ -116,9 +121,9 @@ string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode)
return str;
}
-string EncodeHexTx(const CTransaction& tx, const int serialFlags)
+std::string EncodeHexTx(const CTransaction& tx, const int serializeFlags)
{
- CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION | serialFlags);
+ CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION | serializeFlags);
ssTx << tx;
return HexStr(ssTx.begin(), ssTx.end());
}
@@ -127,7 +132,7 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey,
UniValue& out, bool fIncludeHex)
{
txnouttype type;
- vector<CTxDestination> addresses;
+ std::vector<CTxDestination> addresses;
int nRequired;
out.pushKV("asm", ScriptToAsmStr(scriptPubKey));
@@ -143,16 +148,19 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey,
out.pushKV("type", GetTxnOutputType(type));
UniValue a(UniValue::VARR);
- BOOST_FOREACH(const CTxDestination& addr, addresses)
- a.push_back(CBitcoinAddress(addr).ToString());
+ for (const CTxDestination& addr : addresses) {
+ a.push_back(EncodeDestination(addr));
+ }
out.pushKV("addresses", a);
}
-void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry)
+void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags)
{
entry.pushKV("txid", tx.GetHash().GetHex());
entry.pushKV("hash", tx.GetWitnessHash().GetHex());
entry.pushKV("version", tx.nVersion);
+ entry.pushKV("size", (int)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION));
+ entry.pushKV("vsize", (GetTransactionWeight(tx) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR);
entry.pushKV("locktime", (int64_t)tx.nLockTime);
UniValue vin(UniValue::VARR);
@@ -187,8 +195,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry)
UniValue out(UniValue::VOBJ);
- UniValue outValue(UniValue::VNUM, FormatMoney(txout.nValue));
- out.pushKV("value", outValue);
+ out.pushKV("value", ValueFromAmount(txout.nValue));
out.pushKV("n", (int64_t)i);
UniValue o(UniValue::VOBJ);
@@ -201,5 +208,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry)
if (!hashBlock.IsNull())
entry.pushKV("blockhash", hashBlock.GetHex());
- entry.pushKV("hex", EncodeHexTx(tx)); // the hex-encoded transaction. used the name "hex" to be consistent with the verbose output of "getrawtransaction".
+ if (include_hex) {
+ entry.pushKV("hex", EncodeHexTx(tx, serialize_flags)); // the hex-encoded transaction. used the name "hex" to be consistent with the verbose output of "getrawtransaction".
+ }
}
diff --git a/src/crypto/aes.cpp b/src/crypto/aes.cpp
index 1d469d0fb4..5e70d25eee 100644
--- a/src/crypto/aes.cpp
+++ b/src/crypto/aes.cpp
@@ -112,7 +112,6 @@ static int CBCEncrypt(const T& enc, const unsigned char iv[AES_BLOCKSIZE], const
template <typename T>
static int CBCDecrypt(const T& dec, const unsigned char iv[AES_BLOCKSIZE], const unsigned char* data, int size, bool pad, unsigned char* out)
{
- unsigned char padsize = 0;
int written = 0;
bool fail = false;
const unsigned char* prev = iv;
@@ -136,7 +135,7 @@ static int CBCDecrypt(const T& dec, const unsigned char iv[AES_BLOCKSIZE], const
if (pad) {
// If used, padding size is the value of the last decrypted byte. For
// it to be valid, It must be between 1 and AES_BLOCKSIZE.
- padsize = *--out;
+ unsigned char padsize = *--out;
fail = !padsize | (padsize > AES_BLOCKSIZE);
// If not well-formed, treat it as though there's no padding.
diff --git a/src/crypto/aes.h b/src/crypto/aes.h
index e9f1b52e71..a7b63b19df 100644
--- a/src/crypto/aes.h
+++ b/src/crypto/aes.h
@@ -22,7 +22,7 @@ private:
AES128_ctx ctx;
public:
- AES128Encrypt(const unsigned char key[16]);
+ explicit AES128Encrypt(const unsigned char key[16]);
~AES128Encrypt();
void Encrypt(unsigned char ciphertext[16], const unsigned char plaintext[16]) const;
};
@@ -34,7 +34,7 @@ private:
AES128_ctx ctx;
public:
- AES128Decrypt(const unsigned char key[16]);
+ explicit AES128Decrypt(const unsigned char key[16]);
~AES128Decrypt();
void Decrypt(unsigned char plaintext[16], const unsigned char ciphertext[16]) const;
};
@@ -46,7 +46,7 @@ private:
AES256_ctx ctx;
public:
- AES256Encrypt(const unsigned char key[32]);
+ explicit AES256Encrypt(const unsigned char key[32]);
~AES256Encrypt();
void Encrypt(unsigned char ciphertext[16], const unsigned char plaintext[16]) const;
};
@@ -58,7 +58,7 @@ private:
AES256_ctx ctx;
public:
- AES256Decrypt(const unsigned char key[32]);
+ explicit AES256Decrypt(const unsigned char key[32]);
~AES256Decrypt();
void Decrypt(unsigned char plaintext[16], const unsigned char ciphertext[16]) const;
};
diff --git a/src/crypto/chacha20.cpp b/src/crypto/chacha20.cpp
new file mode 100644
index 0000000000..4038ae9f86
--- /dev/null
+++ b/src/crypto/chacha20.cpp
@@ -0,0 +1,180 @@
+// Copyright (c) 2017 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+// Based on the public domain implementation 'merged' by D. J. Bernstein
+// See https://cr.yp.to/chacha.html.
+
+#include "crypto/common.h"
+#include "crypto/chacha20.h"
+
+#include <string.h>
+
+constexpr static inline uint32_t rotl32(uint32_t v, int c) { return (v << c) | (v >> (32 - c)); }
+
+#define QUARTERROUND(a,b,c,d) \
+ a += b; d = rotl32(d ^ a, 16); \
+ c += d; b = rotl32(b ^ c, 12); \
+ a += b; d = rotl32(d ^ a, 8); \
+ c += d; b = rotl32(b ^ c, 7);
+
+static const unsigned char sigma[] = "expand 32-byte k";
+static const unsigned char tau[] = "expand 16-byte k";
+
+void ChaCha20::SetKey(const unsigned char* k, size_t keylen)
+{
+ const unsigned char *constants;
+
+ input[4] = ReadLE32(k + 0);
+ input[5] = ReadLE32(k + 4);
+ input[6] = ReadLE32(k + 8);
+ input[7] = ReadLE32(k + 12);
+ if (keylen == 32) { /* recommended */
+ k += 16;
+ constants = sigma;
+ } else { /* keylen == 16 */
+ constants = tau;
+ }
+ input[8] = ReadLE32(k + 0);
+ input[9] = ReadLE32(k + 4);
+ input[10] = ReadLE32(k + 8);
+ input[11] = ReadLE32(k + 12);
+ input[0] = ReadLE32(constants + 0);
+ input[1] = ReadLE32(constants + 4);
+ input[2] = ReadLE32(constants + 8);
+ input[3] = ReadLE32(constants + 12);
+ input[12] = 0;
+ input[13] = 0;
+ input[14] = 0;
+ input[15] = 0;
+}
+
+ChaCha20::ChaCha20()
+{
+ memset(input, 0, sizeof(input));
+}
+
+ChaCha20::ChaCha20(const unsigned char* k, size_t keylen)
+{
+ SetKey(k, keylen);
+}
+
+void ChaCha20::SetIV(uint64_t iv)
+{
+ input[14] = iv;
+ input[15] = iv >> 32;
+}
+
+void ChaCha20::Seek(uint64_t pos)
+{
+ input[12] = pos;
+ input[13] = pos >> 32;
+}
+
+void ChaCha20::Output(unsigned char* c, size_t bytes)
+{
+ uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
+ uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
+ unsigned char *ctarget = nullptr;
+ unsigned char tmp[64];
+ unsigned int i;
+
+ if (!bytes) return;
+
+ j0 = input[0];
+ j1 = input[1];
+ j2 = input[2];
+ j3 = input[3];
+ j4 = input[4];
+ j5 = input[5];
+ j6 = input[6];
+ j7 = input[7];
+ j8 = input[8];
+ j9 = input[9];
+ j10 = input[10];
+ j11 = input[11];
+ j12 = input[12];
+ j13 = input[13];
+ j14 = input[14];
+ j15 = input[15];
+
+ for (;;) {
+ if (bytes < 64) {
+ ctarget = c;
+ c = tmp;
+ }
+ x0 = j0;
+ x1 = j1;
+ x2 = j2;
+ x3 = j3;
+ x4 = j4;
+ x5 = j5;
+ x6 = j6;
+ x7 = j7;
+ x8 = j8;
+ x9 = j9;
+ x10 = j10;
+ x11 = j11;
+ x12 = j12;
+ x13 = j13;
+ x14 = j14;
+ x15 = j15;
+ for (i = 20;i > 0;i -= 2) {
+ QUARTERROUND( x0, x4, x8,x12)
+ QUARTERROUND( x1, x5, x9,x13)
+ QUARTERROUND( x2, x6,x10,x14)
+ QUARTERROUND( x3, x7,x11,x15)
+ QUARTERROUND( x0, x5,x10,x15)
+ QUARTERROUND( x1, x6,x11,x12)
+ QUARTERROUND( x2, x7, x8,x13)
+ QUARTERROUND( x3, x4, x9,x14)
+ }
+ x0 += j0;
+ x1 += j1;
+ x2 += j2;
+ x3 += j3;
+ x4 += j4;
+ x5 += j5;
+ x6 += j6;
+ x7 += j7;
+ x8 += j8;
+ x9 += j9;
+ x10 += j10;
+ x11 += j11;
+ x12 += j12;
+ x13 += j13;
+ x14 += j14;
+ x15 += j15;
+
+ ++j12;
+ if (!j12) ++j13;
+
+ WriteLE32(c + 0, x0);
+ WriteLE32(c + 4, x1);
+ WriteLE32(c + 8, x2);
+ WriteLE32(c + 12, x3);
+ WriteLE32(c + 16, x4);
+ WriteLE32(c + 20, x5);
+ WriteLE32(c + 24, x6);
+ WriteLE32(c + 28, x7);
+ WriteLE32(c + 32, x8);
+ WriteLE32(c + 36, x9);
+ WriteLE32(c + 40, x10);
+ WriteLE32(c + 44, x11);
+ WriteLE32(c + 48, x12);
+ WriteLE32(c + 52, x13);
+ WriteLE32(c + 56, x14);
+ WriteLE32(c + 60, x15);
+
+ if (bytes <= 64) {
+ if (bytes < 64) {
+ for (i = 0;i < bytes;++i) ctarget[i] = c[i];
+ }
+ input[12] = j12;
+ input[13] = j13;
+ return;
+ }
+ bytes -= 64;
+ c += 64;
+ }
+}
diff --git a/src/crypto/chacha20.h b/src/crypto/chacha20.h
new file mode 100644
index 0000000000..a305977bcd
--- /dev/null
+++ b/src/crypto/chacha20.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2017 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_CRYPTO_CHACHA20_H
+#define BITCOIN_CRYPTO_CHACHA20_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+/** A PRNG class for ChaCha20. */
+class ChaCha20
+{
+private:
+ uint32_t input[16];
+
+public:
+ ChaCha20();
+ ChaCha20(const unsigned char* key, size_t keylen);
+ void SetKey(const unsigned char* key, size_t keylen);
+ void SetIV(uint64_t iv);
+ void Seek(uint64_t pos);
+ void Output(unsigned char* output, size_t bytes);
+};
+
+#endif // BITCOIN_CRYPTO_CHACHA20_H
diff --git a/src/crypto/common.h b/src/crypto/common.h
index 580c72f5a6..bd9bc9420b 100644
--- a/src/crypto/common.h
+++ b/src/crypto/common.h
@@ -6,61 +6,98 @@
#define BITCOIN_CRYPTO_COMMON_H
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include <stdint.h>
+#include <string.h>
#include "compat/endian.h"
uint16_t static inline ReadLE16(const unsigned char* ptr)
{
- return le16toh(*((uint16_t*)ptr));
+ uint16_t x;
+ memcpy((char*)&x, ptr, 2);
+ return le16toh(x);
}
uint32_t static inline ReadLE32(const unsigned char* ptr)
{
- return le32toh(*((uint32_t*)ptr));
+ uint32_t x;
+ memcpy((char*)&x, ptr, 4);
+ return le32toh(x);
}
uint64_t static inline ReadLE64(const unsigned char* ptr)
{
- return le64toh(*((uint64_t*)ptr));
+ uint64_t x;
+ memcpy((char*)&x, ptr, 8);
+ return le64toh(x);
}
void static inline WriteLE16(unsigned char* ptr, uint16_t x)
{
- *((uint16_t*)ptr) = htole16(x);
+ uint16_t v = htole16(x);
+ memcpy(ptr, (char*)&v, 2);
}
void static inline WriteLE32(unsigned char* ptr, uint32_t x)
{
- *((uint32_t*)ptr) = htole32(x);
+ uint32_t v = htole32(x);
+ memcpy(ptr, (char*)&v, 4);
}
void static inline WriteLE64(unsigned char* ptr, uint64_t x)
{
- *((uint64_t*)ptr) = htole64(x);
+ uint64_t v = htole64(x);
+ memcpy(ptr, (char*)&v, 8);
}
uint32_t static inline ReadBE32(const unsigned char* ptr)
{
- return be32toh(*((uint32_t*)ptr));
+ uint32_t x;
+ memcpy((char*)&x, ptr, 4);
+ return be32toh(x);
}
uint64_t static inline ReadBE64(const unsigned char* ptr)
{
- return be64toh(*((uint64_t*)ptr));
+ uint64_t x;
+ memcpy((char*)&x, ptr, 8);
+ return be64toh(x);
}
void static inline WriteBE32(unsigned char* ptr, uint32_t x)
{
- *((uint32_t*)ptr) = htobe32(x);
+ uint32_t v = htobe32(x);
+ memcpy(ptr, (char*)&v, 4);
}
void static inline WriteBE64(unsigned char* ptr, uint64_t x)
{
- *((uint64_t*)ptr) = htobe64(x);
+ uint64_t v = htobe64(x);
+ memcpy(ptr, (char*)&v, 8);
+}
+
+/** Return the smallest number n such that (x >> n) == 0 (or 64 if the highest bit in x is set. */
+uint64_t static inline CountBits(uint64_t x)
+{
+#ifdef HAVE_DECL___BUILTIN_CLZL
+ if (sizeof(unsigned long) >= sizeof(uint64_t)) {
+ return x ? 8 * sizeof(unsigned long) - __builtin_clzl(x) : 0;
+ }
+#endif
+#ifdef HAVE_DECL___BUILTIN_CLZLL
+ if (sizeof(unsigned long long) >= sizeof(uint64_t)) {
+ return x ? 8 * sizeof(unsigned long long) - __builtin_clzll(x) : 0;
+ }
+#endif
+ int ret = 0;
+ while (x) {
+ x >>= 1;
+ ++ret;
+ }
+ return ret;
}
#endif // BITCOIN_CRYPTO_COMMON_H
diff --git a/src/crypto/hmac_sha256.h b/src/crypto/hmac_sha256.h
index 1519c1457e..8c42fcfe14 100644
--- a/src/crypto/hmac_sha256.h
+++ b/src/crypto/hmac_sha256.h
@@ -10,7 +10,7 @@
#include <stdint.h>
#include <stdlib.h>
-/** A hasher class for HMAC-SHA-512. */
+/** A hasher class for HMAC-SHA-256. */
class CHMAC_SHA256
{
private:
diff --git a/src/crypto/sha256.cpp b/src/crypto/sha256.cpp
index 5b9f00a0a2..29afe86ec7 100644
--- a/src/crypto/sha256.cpp
+++ b/src/crypto/sha256.cpp
@@ -3,10 +3,21 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "crypto/sha256.h"
-
#include "crypto/common.h"
+#include <assert.h>
#include <string.h>
+#include <atomic>
+
+#if defined(__x86_64__) || defined(__amd64__)
+#if defined(USE_ASM)
+#include <cpuid.h>
+namespace sha256_sse4
+{
+void Transform(uint32_t* s, const unsigned char* chunk, size_t blocks);
+}
+#endif
+#endif
// Internal implementation code.
namespace
@@ -43,93 +54,142 @@ void inline Initialize(uint32_t* s)
s[7] = 0x5be0cd19ul;
}
-/** Perform one SHA-256 transformation, processing a 64-byte chunk. */
-void Transform(uint32_t* s, const unsigned char* chunk)
+/** Perform a number of SHA-256 transformations, processing 64-byte chunks. */
+void Transform(uint32_t* s, const unsigned char* chunk, size_t blocks)
{
- uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];
- uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15;
-
- Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = ReadBE32(chunk + 0));
- Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = ReadBE32(chunk + 4));
- Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = ReadBE32(chunk + 8));
- Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = ReadBE32(chunk + 12));
- Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = ReadBE32(chunk + 16));
- Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = ReadBE32(chunk + 20));
- Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = ReadBE32(chunk + 24));
- Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = ReadBE32(chunk + 28));
- Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = ReadBE32(chunk + 32));
- Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = ReadBE32(chunk + 36));
- Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = ReadBE32(chunk + 40));
- Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = ReadBE32(chunk + 44));
- Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = ReadBE32(chunk + 48));
- Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = ReadBE32(chunk + 52));
- Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = ReadBE32(chunk + 56));
- Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = ReadBE32(chunk + 60));
-
- Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1));
- Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2));
- Round(g, h, a, b, c, d, e, f, 0x0fc19dc6, w2 += sigma1(w0) + w11 + sigma0(w3));
- Round(f, g, h, a, b, c, d, e, 0x240ca1cc, w3 += sigma1(w1) + w12 + sigma0(w4));
- Round(e, f, g, h, a, b, c, d, 0x2de92c6f, w4 += sigma1(w2) + w13 + sigma0(w5));
- Round(d, e, f, g, h, a, b, c, 0x4a7484aa, w5 += sigma1(w3) + w14 + sigma0(w6));
- Round(c, d, e, f, g, h, a, b, 0x5cb0a9dc, w6 += sigma1(w4) + w15 + sigma0(w7));
- Round(b, c, d, e, f, g, h, a, 0x76f988da, w7 += sigma1(w5) + w0 + sigma0(w8));
- Round(a, b, c, d, e, f, g, h, 0x983e5152, w8 += sigma1(w6) + w1 + sigma0(w9));
- Round(h, a, b, c, d, e, f, g, 0xa831c66d, w9 += sigma1(w7) + w2 + sigma0(w10));
- Round(g, h, a, b, c, d, e, f, 0xb00327c8, w10 += sigma1(w8) + w3 + sigma0(w11));
- Round(f, g, h, a, b, c, d, e, 0xbf597fc7, w11 += sigma1(w9) + w4 + sigma0(w12));
- Round(e, f, g, h, a, b, c, d, 0xc6e00bf3, w12 += sigma1(w10) + w5 + sigma0(w13));
- Round(d, e, f, g, h, a, b, c, 0xd5a79147, w13 += sigma1(w11) + w6 + sigma0(w14));
- Round(c, d, e, f, g, h, a, b, 0x06ca6351, w14 += sigma1(w12) + w7 + sigma0(w15));
- Round(b, c, d, e, f, g, h, a, 0x14292967, w15 += sigma1(w13) + w8 + sigma0(w0));
-
- Round(a, b, c, d, e, f, g, h, 0x27b70a85, w0 += sigma1(w14) + w9 + sigma0(w1));
- Round(h, a, b, c, d, e, f, g, 0x2e1b2138, w1 += sigma1(w15) + w10 + sigma0(w2));
- Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc, w2 += sigma1(w0) + w11 + sigma0(w3));
- Round(f, g, h, a, b, c, d, e, 0x53380d13, w3 += sigma1(w1) + w12 + sigma0(w4));
- Round(e, f, g, h, a, b, c, d, 0x650a7354, w4 += sigma1(w2) + w13 + sigma0(w5));
- Round(d, e, f, g, h, a, b, c, 0x766a0abb, w5 += sigma1(w3) + w14 + sigma0(w6));
- Round(c, d, e, f, g, h, a, b, 0x81c2c92e, w6 += sigma1(w4) + w15 + sigma0(w7));
- Round(b, c, d, e, f, g, h, a, 0x92722c85, w7 += sigma1(w5) + w0 + sigma0(w8));
- Round(a, b, c, d, e, f, g, h, 0xa2bfe8a1, w8 += sigma1(w6) + w1 + sigma0(w9));
- Round(h, a, b, c, d, e, f, g, 0xa81a664b, w9 += sigma1(w7) + w2 + sigma0(w10));
- Round(g, h, a, b, c, d, e, f, 0xc24b8b70, w10 += sigma1(w8) + w3 + sigma0(w11));
- Round(f, g, h, a, b, c, d, e, 0xc76c51a3, w11 += sigma1(w9) + w4 + sigma0(w12));
- Round(e, f, g, h, a, b, c, d, 0xd192e819, w12 += sigma1(w10) + w5 + sigma0(w13));
- Round(d, e, f, g, h, a, b, c, 0xd6990624, w13 += sigma1(w11) + w6 + sigma0(w14));
- Round(c, d, e, f, g, h, a, b, 0xf40e3585, w14 += sigma1(w12) + w7 + sigma0(w15));
- Round(b, c, d, e, f, g, h, a, 0x106aa070, w15 += sigma1(w13) + w8 + sigma0(w0));
-
- Round(a, b, c, d, e, f, g, h, 0x19a4c116, w0 += sigma1(w14) + w9 + sigma0(w1));
- Round(h, a, b, c, d, e, f, g, 0x1e376c08, w1 += sigma1(w15) + w10 + sigma0(w2));
- Round(g, h, a, b, c, d, e, f, 0x2748774c, w2 += sigma1(w0) + w11 + sigma0(w3));
- Round(f, g, h, a, b, c, d, e, 0x34b0bcb5, w3 += sigma1(w1) + w12 + sigma0(w4));
- Round(e, f, g, h, a, b, c, d, 0x391c0cb3, w4 += sigma1(w2) + w13 + sigma0(w5));
- Round(d, e, f, g, h, a, b, c, 0x4ed8aa4a, w5 += sigma1(w3) + w14 + sigma0(w6));
- Round(c, d, e, f, g, h, a, b, 0x5b9cca4f, w6 += sigma1(w4) + w15 + sigma0(w7));
- Round(b, c, d, e, f, g, h, a, 0x682e6ff3, w7 += sigma1(w5) + w0 + sigma0(w8));
- Round(a, b, c, d, e, f, g, h, 0x748f82ee, w8 += sigma1(w6) + w1 + sigma0(w9));
- Round(h, a, b, c, d, e, f, g, 0x78a5636f, w9 += sigma1(w7) + w2 + sigma0(w10));
- Round(g, h, a, b, c, d, e, f, 0x84c87814, w10 += sigma1(w8) + w3 + sigma0(w11));
- Round(f, g, h, a, b, c, d, e, 0x8cc70208, w11 += sigma1(w9) + w4 + sigma0(w12));
- Round(e, f, g, h, a, b, c, d, 0x90befffa, w12 += sigma1(w10) + w5 + sigma0(w13));
- Round(d, e, f, g, h, a, b, c, 0xa4506ceb, w13 += sigma1(w11) + w6 + sigma0(w14));
- Round(c, d, e, f, g, h, a, b, 0xbef9a3f7, w14 + sigma1(w12) + w7 + sigma0(w15));
- Round(b, c, d, e, f, g, h, a, 0xc67178f2, w15 + sigma1(w13) + w8 + sigma0(w0));
-
- s[0] += a;
- s[1] += b;
- s[2] += c;
- s[3] += d;
- s[4] += e;
- s[5] += f;
- s[6] += g;
- s[7] += h;
+ while (blocks--) {
+ uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];
+ uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15;
+
+ Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = ReadBE32(chunk + 0));
+ Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = ReadBE32(chunk + 4));
+ Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = ReadBE32(chunk + 8));
+ Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = ReadBE32(chunk + 12));
+ Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = ReadBE32(chunk + 16));
+ Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = ReadBE32(chunk + 20));
+ Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = ReadBE32(chunk + 24));
+ Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = ReadBE32(chunk + 28));
+ Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = ReadBE32(chunk + 32));
+ Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = ReadBE32(chunk + 36));
+ Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = ReadBE32(chunk + 40));
+ Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = ReadBE32(chunk + 44));
+ Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = ReadBE32(chunk + 48));
+ Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = ReadBE32(chunk + 52));
+ Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = ReadBE32(chunk + 56));
+ Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = ReadBE32(chunk + 60));
+
+ Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1));
+ Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2));
+ Round(g, h, a, b, c, d, e, f, 0x0fc19dc6, w2 += sigma1(w0) + w11 + sigma0(w3));
+ Round(f, g, h, a, b, c, d, e, 0x240ca1cc, w3 += sigma1(w1) + w12 + sigma0(w4));
+ Round(e, f, g, h, a, b, c, d, 0x2de92c6f, w4 += sigma1(w2) + w13 + sigma0(w5));
+ Round(d, e, f, g, h, a, b, c, 0x4a7484aa, w5 += sigma1(w3) + w14 + sigma0(w6));
+ Round(c, d, e, f, g, h, a, b, 0x5cb0a9dc, w6 += sigma1(w4) + w15 + sigma0(w7));
+ Round(b, c, d, e, f, g, h, a, 0x76f988da, w7 += sigma1(w5) + w0 + sigma0(w8));
+ Round(a, b, c, d, e, f, g, h, 0x983e5152, w8 += sigma1(w6) + w1 + sigma0(w9));
+ Round(h, a, b, c, d, e, f, g, 0xa831c66d, w9 += sigma1(w7) + w2 + sigma0(w10));
+ Round(g, h, a, b, c, d, e, f, 0xb00327c8, w10 += sigma1(w8) + w3 + sigma0(w11));
+ Round(f, g, h, a, b, c, d, e, 0xbf597fc7, w11 += sigma1(w9) + w4 + sigma0(w12));
+ Round(e, f, g, h, a, b, c, d, 0xc6e00bf3, w12 += sigma1(w10) + w5 + sigma0(w13));
+ Round(d, e, f, g, h, a, b, c, 0xd5a79147, w13 += sigma1(w11) + w6 + sigma0(w14));
+ Round(c, d, e, f, g, h, a, b, 0x06ca6351, w14 += sigma1(w12) + w7 + sigma0(w15));
+ Round(b, c, d, e, f, g, h, a, 0x14292967, w15 += sigma1(w13) + w8 + sigma0(w0));
+
+ Round(a, b, c, d, e, f, g, h, 0x27b70a85, w0 += sigma1(w14) + w9 + sigma0(w1));
+ Round(h, a, b, c, d, e, f, g, 0x2e1b2138, w1 += sigma1(w15) + w10 + sigma0(w2));
+ Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc, w2 += sigma1(w0) + w11 + sigma0(w3));
+ Round(f, g, h, a, b, c, d, e, 0x53380d13, w3 += sigma1(w1) + w12 + sigma0(w4));
+ Round(e, f, g, h, a, b, c, d, 0x650a7354, w4 += sigma1(w2) + w13 + sigma0(w5));
+ Round(d, e, f, g, h, a, b, c, 0x766a0abb, w5 += sigma1(w3) + w14 + sigma0(w6));
+ Round(c, d, e, f, g, h, a, b, 0x81c2c92e, w6 += sigma1(w4) + w15 + sigma0(w7));
+ Round(b, c, d, e, f, g, h, a, 0x92722c85, w7 += sigma1(w5) + w0 + sigma0(w8));
+ Round(a, b, c, d, e, f, g, h, 0xa2bfe8a1, w8 += sigma1(w6) + w1 + sigma0(w9));
+ Round(h, a, b, c, d, e, f, g, 0xa81a664b, w9 += sigma1(w7) + w2 + sigma0(w10));
+ Round(g, h, a, b, c, d, e, f, 0xc24b8b70, w10 += sigma1(w8) + w3 + sigma0(w11));
+ Round(f, g, h, a, b, c, d, e, 0xc76c51a3, w11 += sigma1(w9) + w4 + sigma0(w12));
+ Round(e, f, g, h, a, b, c, d, 0xd192e819, w12 += sigma1(w10) + w5 + sigma0(w13));
+ Round(d, e, f, g, h, a, b, c, 0xd6990624, w13 += sigma1(w11) + w6 + sigma0(w14));
+ Round(c, d, e, f, g, h, a, b, 0xf40e3585, w14 += sigma1(w12) + w7 + sigma0(w15));
+ Round(b, c, d, e, f, g, h, a, 0x106aa070, w15 += sigma1(w13) + w8 + sigma0(w0));
+
+ Round(a, b, c, d, e, f, g, h, 0x19a4c116, w0 += sigma1(w14) + w9 + sigma0(w1));
+ Round(h, a, b, c, d, e, f, g, 0x1e376c08, w1 += sigma1(w15) + w10 + sigma0(w2));
+ Round(g, h, a, b, c, d, e, f, 0x2748774c, w2 += sigma1(w0) + w11 + sigma0(w3));
+ Round(f, g, h, a, b, c, d, e, 0x34b0bcb5, w3 += sigma1(w1) + w12 + sigma0(w4));
+ Round(e, f, g, h, a, b, c, d, 0x391c0cb3, w4 += sigma1(w2) + w13 + sigma0(w5));
+ Round(d, e, f, g, h, a, b, c, 0x4ed8aa4a, w5 += sigma1(w3) + w14 + sigma0(w6));
+ Round(c, d, e, f, g, h, a, b, 0x5b9cca4f, w6 += sigma1(w4) + w15 + sigma0(w7));
+ Round(b, c, d, e, f, g, h, a, 0x682e6ff3, w7 += sigma1(w5) + w0 + sigma0(w8));
+ Round(a, b, c, d, e, f, g, h, 0x748f82ee, w8 += sigma1(w6) + w1 + sigma0(w9));
+ Round(h, a, b, c, d, e, f, g, 0x78a5636f, w9 += sigma1(w7) + w2 + sigma0(w10));
+ Round(g, h, a, b, c, d, e, f, 0x84c87814, w10 += sigma1(w8) + w3 + sigma0(w11));
+ Round(f, g, h, a, b, c, d, e, 0x8cc70208, w11 += sigma1(w9) + w4 + sigma0(w12));
+ Round(e, f, g, h, a, b, c, d, 0x90befffa, w12 += sigma1(w10) + w5 + sigma0(w13));
+ Round(d, e, f, g, h, a, b, c, 0xa4506ceb, w13 += sigma1(w11) + w6 + sigma0(w14));
+ Round(c, d, e, f, g, h, a, b, 0xbef9a3f7, w14 + sigma1(w12) + w7 + sigma0(w15));
+ Round(b, c, d, e, f, g, h, a, 0xc67178f2, w15 + sigma1(w13) + w8 + sigma0(w0));
+
+ s[0] += a;
+ s[1] += b;
+ s[2] += c;
+ s[3] += d;
+ s[4] += e;
+ s[5] += f;
+ s[6] += g;
+ s[7] += h;
+ chunk += 64;
+ }
}
} // namespace sha256
+
+typedef void (*TransformType)(uint32_t*, const unsigned char*, size_t);
+
+bool SelfTest(TransformType tr) {
+ static const unsigned char in1[65] = {0, 0x80};
+ static const unsigned char in2[129] = {
+ 0,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0
+ };
+ static const uint32_t init[8] = {0x6a09e667ul, 0xbb67ae85ul, 0x3c6ef372ul, 0xa54ff53aul, 0x510e527ful, 0x9b05688cul, 0x1f83d9abul, 0x5be0cd19ul};
+ static const uint32_t out1[8] = {0xe3b0c442ul, 0x98fc1c14ul, 0x9afbf4c8ul, 0x996fb924ul, 0x27ae41e4ul, 0x649b934cul, 0xa495991bul, 0x7852b855ul};
+ static const uint32_t out2[8] = {0xce4153b0ul, 0x147c2a86ul, 0x3ed4298eul, 0xe0676bc8ul, 0x79fc77a1ul, 0x2abe1f49ul, 0xb2b055dful, 0x1069523eul};
+ uint32_t buf[8];
+ memcpy(buf, init, sizeof(buf));
+ // Process nothing, and check we remain in the initial state.
+ tr(buf, nullptr, 0);
+ if (memcmp(buf, init, sizeof(buf))) return false;
+ // Process the padded empty string (unaligned)
+ tr(buf, in1 + 1, 1);
+ if (memcmp(buf, out1, sizeof(buf))) return false;
+ // Process 64 spaces (unaligned)
+ memcpy(buf, init, sizeof(buf));
+ tr(buf, in2 + 1, 2);
+ if (memcmp(buf, out2, sizeof(buf))) return false;
+ return true;
+}
+
+TransformType Transform = sha256::Transform;
+
} // namespace
+std::string SHA256AutoDetect()
+{
+#if defined(USE_ASM) && (defined(__x86_64__) || defined(__amd64__))
+ uint32_t eax, ebx, ecx, edx;
+ if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) && (ecx >> 19) & 1) {
+ Transform = sha256_sse4::Transform;
+ assert(SelfTest(Transform));
+ return "sse4";
+ }
+#endif
+
+ assert(SelfTest(Transform));
+ return "standard";
+}
////// SHA-256
@@ -147,14 +207,14 @@ CSHA256& CSHA256::Write(const unsigned char* data, size_t len)
memcpy(buf + bufsize, data, 64 - bufsize);
bytes += 64 - bufsize;
data += 64 - bufsize;
- sha256::Transform(s, buf);
+ Transform(s, buf, 1);
bufsize = 0;
}
- while (end >= data + 64) {
- // Process full chunks directly from the source.
- sha256::Transform(s, data);
- bytes += 64;
- data += 64;
+ if (end - data >= 64) {
+ size_t blocks = (end - data) / 64;
+ Transform(s, data, blocks);
+ data += 64 * blocks;
+ bytes += 64 * blocks;
}
if (end > data) {
// Fill the buffer with what remains.
diff --git a/src/crypto/sha256.h b/src/crypto/sha256.h
index 127e62a228..aa4f3972cc 100644
--- a/src/crypto/sha256.h
+++ b/src/crypto/sha256.h
@@ -7,6 +7,7 @@
#include <stdint.h>
#include <stdlib.h>
+#include <string>
/** A hasher class for SHA-256. */
class CSHA256
@@ -25,4 +26,9 @@ public:
CSHA256& Reset();
};
+/** Autodetect the best available SHA256 implementation.
+ * Returns the name of the implementation.
+ */
+std::string SHA256AutoDetect();
+
#endif // BITCOIN_CRYPTO_SHA256_H
diff --git a/src/crypto/sha256_sse4.cpp b/src/crypto/sha256_sse4.cpp
new file mode 100644
index 0000000000..89f529a3ab
--- /dev/null
+++ b/src/crypto/sha256_sse4.cpp
@@ -0,0 +1,1506 @@
+// Copyright (c) 2017 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+//
+// This is a translation to GCC extended asm syntax from YASM code by Intel
+// (available at the bottom of this file).
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#if defined(__x86_64__) || defined(__amd64__)
+
+namespace sha256_sse4
+{
+void Transform(uint32_t* s, const unsigned char* chunk, size_t blocks)
+{
+ static const uint32_t K256 alignas(16) [] = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+ 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+ 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+ 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+ 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
+ };
+ static const uint32_t FLIP_MASK alignas(16) [] = {0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f};
+ static const uint32_t SHUF_00BA alignas(16) [] = {0x03020100, 0x0b0a0908, 0xffffffff, 0xffffffff};
+ static const uint32_t SHUF_DC00 alignas(16) [] = {0xffffffff, 0xffffffff, 0x03020100, 0x0b0a0908};
+ uint32_t a, b, c, d, f, g, h, y0, y1, y2;
+ uint64_t tbl;
+ uint64_t inp_end, inp;
+ uint32_t xfer alignas(16) [4];
+
+ __asm__ __volatile__(
+ "shl $0x6,%2;"
+ "je Ldone_hash_%=;"
+ "add %1,%2;"
+ "mov %2,%14;"
+ "mov (%0),%3;"
+ "mov 0x4(%0),%4;"
+ "mov 0x8(%0),%5;"
+ "mov 0xc(%0),%6;"
+ "mov 0x10(%0),%k2;"
+ "mov 0x14(%0),%7;"
+ "mov 0x18(%0),%8;"
+ "mov 0x1c(%0),%9;"
+ "movdqa %18,%%xmm12;"
+ "movdqa %19,%%xmm10;"
+ "movdqa %20,%%xmm11;"
+
+ "Lloop0_%=:"
+ "lea %17,%13;"
+ "movdqu (%1),%%xmm4;"
+ "pshufb %%xmm12,%%xmm4;"
+ "movdqu 0x10(%1),%%xmm5;"
+ "pshufb %%xmm12,%%xmm5;"
+ "movdqu 0x20(%1),%%xmm6;"
+ "pshufb %%xmm12,%%xmm6;"
+ "movdqu 0x30(%1),%%xmm7;"
+ "pshufb %%xmm12,%%xmm7;"
+ "mov %1,%15;"
+ "mov $3,%1;"
+
+ "Lloop1_%=:"
+ "movdqa 0x0(%13),%%xmm9;"
+ "paddd %%xmm4,%%xmm9;"
+ "movdqa %%xmm9,%16;"
+ "movdqa %%xmm7,%%xmm0;"
+ "mov %k2,%10;"
+ "ror $0xe,%10;"
+ "mov %3,%11;"
+ "palignr $0x4,%%xmm6,%%xmm0;"
+ "ror $0x9,%11;"
+ "xor %k2,%10;"
+ "mov %7,%12;"
+ "ror $0x5,%10;"
+ "movdqa %%xmm5,%%xmm1;"
+ "xor %3,%11;"
+ "xor %8,%12;"
+ "paddd %%xmm4,%%xmm0;"
+ "xor %k2,%10;"
+ "and %k2,%12;"
+ "ror $0xb,%11;"
+ "palignr $0x4,%%xmm4,%%xmm1;"
+ "xor %3,%11;"
+ "ror $0x6,%10;"
+ "xor %8,%12;"
+ "movdqa %%xmm1,%%xmm2;"
+ "ror $0x2,%11;"
+ "add %10,%12;"
+ "add %16,%12;"
+ "movdqa %%xmm1,%%xmm3;"
+ "mov %3,%10;"
+ "add %12,%9;"
+ "mov %3,%12;"
+ "pslld $0x19,%%xmm1;"
+ "or %5,%10;"
+ "add %9,%6;"
+ "and %5,%12;"
+ "psrld $0x7,%%xmm2;"
+ "and %4,%10;"
+ "add %11,%9;"
+ "por %%xmm2,%%xmm1;"
+ "or %12,%10;"
+ "add %10,%9;"
+ "movdqa %%xmm3,%%xmm2;"
+ "mov %6,%10;"
+ "mov %9,%11;"
+ "movdqa %%xmm3,%%xmm8;"
+ "ror $0xe,%10;"
+ "xor %6,%10;"
+ "mov %k2,%12;"
+ "ror $0x9,%11;"
+ "pslld $0xe,%%xmm3;"
+ "xor %9,%11;"
+ "ror $0x5,%10;"
+ "xor %7,%12;"
+ "psrld $0x12,%%xmm2;"
+ "ror $0xb,%11;"
+ "xor %6,%10;"
+ "and %6,%12;"
+ "ror $0x6,%10;"
+ "pxor %%xmm3,%%xmm1;"
+ "xor %9,%11;"
+ "xor %7,%12;"
+ "psrld $0x3,%%xmm8;"
+ "add %10,%12;"
+ "add 4+%16,%12;"
+ "ror $0x2,%11;"
+ "pxor %%xmm2,%%xmm1;"
+ "mov %9,%10;"
+ "add %12,%8;"
+ "mov %9,%12;"
+ "pxor %%xmm8,%%xmm1;"
+ "or %4,%10;"
+ "add %8,%5;"
+ "and %4,%12;"
+ "pshufd $0xfa,%%xmm7,%%xmm2;"
+ "and %3,%10;"
+ "add %11,%8;"
+ "paddd %%xmm1,%%xmm0;"
+ "or %12,%10;"
+ "add %10,%8;"
+ "movdqa %%xmm2,%%xmm3;"
+ "mov %5,%10;"
+ "mov %8,%11;"
+ "ror $0xe,%10;"
+ "movdqa %%xmm2,%%xmm8;"
+ "xor %5,%10;"
+ "ror $0x9,%11;"
+ "mov %6,%12;"
+ "xor %8,%11;"
+ "ror $0x5,%10;"
+ "psrlq $0x11,%%xmm2;"
+ "xor %k2,%12;"
+ "psrlq $0x13,%%xmm3;"
+ "xor %5,%10;"
+ "and %5,%12;"
+ "psrld $0xa,%%xmm8;"
+ "ror $0xb,%11;"
+ "xor %8,%11;"
+ "xor %k2,%12;"
+ "ror $0x6,%10;"
+ "pxor %%xmm3,%%xmm2;"
+ "add %10,%12;"
+ "ror $0x2,%11;"
+ "add 8+%16,%12;"
+ "pxor %%xmm2,%%xmm8;"
+ "mov %8,%10;"
+ "add %12,%7;"
+ "mov %8,%12;"
+ "pshufb %%xmm10,%%xmm8;"
+ "or %3,%10;"
+ "add %7,%4;"
+ "and %3,%12;"
+ "paddd %%xmm8,%%xmm0;"
+ "and %9,%10;"
+ "add %11,%7;"
+ "pshufd $0x50,%%xmm0,%%xmm2;"
+ "or %12,%10;"
+ "add %10,%7;"
+ "movdqa %%xmm2,%%xmm3;"
+ "mov %4,%10;"
+ "ror $0xe,%10;"
+ "mov %7,%11;"
+ "movdqa %%xmm2,%%xmm4;"
+ "ror $0x9,%11;"
+ "xor %4,%10;"
+ "mov %5,%12;"
+ "ror $0x5,%10;"
+ "psrlq $0x11,%%xmm2;"
+ "xor %7,%11;"
+ "xor %6,%12;"
+ "psrlq $0x13,%%xmm3;"
+ "xor %4,%10;"
+ "and %4,%12;"
+ "ror $0xb,%11;"
+ "psrld $0xa,%%xmm4;"
+ "xor %7,%11;"
+ "ror $0x6,%10;"
+ "xor %6,%12;"
+ "pxor %%xmm3,%%xmm2;"
+ "ror $0x2,%11;"
+ "add %10,%12;"
+ "add 12+%16,%12;"
+ "pxor %%xmm2,%%xmm4;"
+ "mov %7,%10;"
+ "add %12,%k2;"
+ "mov %7,%12;"
+ "pshufb %%xmm11,%%xmm4;"
+ "or %9,%10;"
+ "add %k2,%3;"
+ "and %9,%12;"
+ "paddd %%xmm0,%%xmm4;"
+ "and %8,%10;"
+ "add %11,%k2;"
+ "or %12,%10;"
+ "add %10,%k2;"
+ "movdqa 0x10(%13),%%xmm9;"
+ "paddd %%xmm5,%%xmm9;"
+ "movdqa %%xmm9,%16;"
+ "movdqa %%xmm4,%%xmm0;"
+ "mov %3,%10;"
+ "ror $0xe,%10;"
+ "mov %k2,%11;"
+ "palignr $0x4,%%xmm7,%%xmm0;"
+ "ror $0x9,%11;"
+ "xor %3,%10;"
+ "mov %4,%12;"
+ "ror $0x5,%10;"
+ "movdqa %%xmm6,%%xmm1;"
+ "xor %k2,%11;"
+ "xor %5,%12;"
+ "paddd %%xmm5,%%xmm0;"
+ "xor %3,%10;"
+ "and %3,%12;"
+ "ror $0xb,%11;"
+ "palignr $0x4,%%xmm5,%%xmm1;"
+ "xor %k2,%11;"
+ "ror $0x6,%10;"
+ "xor %5,%12;"
+ "movdqa %%xmm1,%%xmm2;"
+ "ror $0x2,%11;"
+ "add %10,%12;"
+ "add %16,%12;"
+ "movdqa %%xmm1,%%xmm3;"
+ "mov %k2,%10;"
+ "add %12,%6;"
+ "mov %k2,%12;"
+ "pslld $0x19,%%xmm1;"
+ "or %8,%10;"
+ "add %6,%9;"
+ "and %8,%12;"
+ "psrld $0x7,%%xmm2;"
+ "and %7,%10;"
+ "add %11,%6;"
+ "por %%xmm2,%%xmm1;"
+ "or %12,%10;"
+ "add %10,%6;"
+ "movdqa %%xmm3,%%xmm2;"
+ "mov %9,%10;"
+ "mov %6,%11;"
+ "movdqa %%xmm3,%%xmm8;"
+ "ror $0xe,%10;"
+ "xor %9,%10;"
+ "mov %3,%12;"
+ "ror $0x9,%11;"
+ "pslld $0xe,%%xmm3;"
+ "xor %6,%11;"
+ "ror $0x5,%10;"
+ "xor %4,%12;"
+ "psrld $0x12,%%xmm2;"
+ "ror $0xb,%11;"
+ "xor %9,%10;"
+ "and %9,%12;"
+ "ror $0x6,%10;"
+ "pxor %%xmm3,%%xmm1;"
+ "xor %6,%11;"
+ "xor %4,%12;"
+ "psrld $0x3,%%xmm8;"
+ "add %10,%12;"
+ "add 4+%16,%12;"
+ "ror $0x2,%11;"
+ "pxor %%xmm2,%%xmm1;"
+ "mov %6,%10;"
+ "add %12,%5;"
+ "mov %6,%12;"
+ "pxor %%xmm8,%%xmm1;"
+ "or %7,%10;"
+ "add %5,%8;"
+ "and %7,%12;"
+ "pshufd $0xfa,%%xmm4,%%xmm2;"
+ "and %k2,%10;"
+ "add %11,%5;"
+ "paddd %%xmm1,%%xmm0;"
+ "or %12,%10;"
+ "add %10,%5;"
+ "movdqa %%xmm2,%%xmm3;"
+ "mov %8,%10;"
+ "mov %5,%11;"
+ "ror $0xe,%10;"
+ "movdqa %%xmm2,%%xmm8;"
+ "xor %8,%10;"
+ "ror $0x9,%11;"
+ "mov %9,%12;"
+ "xor %5,%11;"
+ "ror $0x5,%10;"
+ "psrlq $0x11,%%xmm2;"
+ "xor %3,%12;"
+ "psrlq $0x13,%%xmm3;"
+ "xor %8,%10;"
+ "and %8,%12;"
+ "psrld $0xa,%%xmm8;"
+ "ror $0xb,%11;"
+ "xor %5,%11;"
+ "xor %3,%12;"
+ "ror $0x6,%10;"
+ "pxor %%xmm3,%%xmm2;"
+ "add %10,%12;"
+ "ror $0x2,%11;"
+ "add 8+%16,%12;"
+ "pxor %%xmm2,%%xmm8;"
+ "mov %5,%10;"
+ "add %12,%4;"
+ "mov %5,%12;"
+ "pshufb %%xmm10,%%xmm8;"
+ "or %k2,%10;"
+ "add %4,%7;"
+ "and %k2,%12;"
+ "paddd %%xmm8,%%xmm0;"
+ "and %6,%10;"
+ "add %11,%4;"
+ "pshufd $0x50,%%xmm0,%%xmm2;"
+ "or %12,%10;"
+ "add %10,%4;"
+ "movdqa %%xmm2,%%xmm3;"
+ "mov %7,%10;"
+ "ror $0xe,%10;"
+ "mov %4,%11;"
+ "movdqa %%xmm2,%%xmm5;"
+ "ror $0x9,%11;"
+ "xor %7,%10;"
+ "mov %8,%12;"
+ "ror $0x5,%10;"
+ "psrlq $0x11,%%xmm2;"
+ "xor %4,%11;"
+ "xor %9,%12;"
+ "psrlq $0x13,%%xmm3;"
+ "xor %7,%10;"
+ "and %7,%12;"
+ "ror $0xb,%11;"
+ "psrld $0xa,%%xmm5;"
+ "xor %4,%11;"
+ "ror $0x6,%10;"
+ "xor %9,%12;"
+ "pxor %%xmm3,%%xmm2;"
+ "ror $0x2,%11;"
+ "add %10,%12;"
+ "add 12+%16,%12;"
+ "pxor %%xmm2,%%xmm5;"
+ "mov %4,%10;"
+ "add %12,%3;"
+ "mov %4,%12;"
+ "pshufb %%xmm11,%%xmm5;"
+ "or %6,%10;"
+ "add %3,%k2;"
+ "and %6,%12;"
+ "paddd %%xmm0,%%xmm5;"
+ "and %5,%10;"
+ "add %11,%3;"
+ "or %12,%10;"
+ "add %10,%3;"
+ "movdqa 0x20(%13),%%xmm9;"
+ "paddd %%xmm6,%%xmm9;"
+ "movdqa %%xmm9,%16;"
+ "movdqa %%xmm5,%%xmm0;"
+ "mov %k2,%10;"
+ "ror $0xe,%10;"
+ "mov %3,%11;"
+ "palignr $0x4,%%xmm4,%%xmm0;"
+ "ror $0x9,%11;"
+ "xor %k2,%10;"
+ "mov %7,%12;"
+ "ror $0x5,%10;"
+ "movdqa %%xmm7,%%xmm1;"
+ "xor %3,%11;"
+ "xor %8,%12;"
+ "paddd %%xmm6,%%xmm0;"
+ "xor %k2,%10;"
+ "and %k2,%12;"
+ "ror $0xb,%11;"
+ "palignr $0x4,%%xmm6,%%xmm1;"
+ "xor %3,%11;"
+ "ror $0x6,%10;"
+ "xor %8,%12;"
+ "movdqa %%xmm1,%%xmm2;"
+ "ror $0x2,%11;"
+ "add %10,%12;"
+ "add %16,%12;"
+ "movdqa %%xmm1,%%xmm3;"
+ "mov %3,%10;"
+ "add %12,%9;"
+ "mov %3,%12;"
+ "pslld $0x19,%%xmm1;"
+ "or %5,%10;"
+ "add %9,%6;"
+ "and %5,%12;"
+ "psrld $0x7,%%xmm2;"
+ "and %4,%10;"
+ "add %11,%9;"
+ "por %%xmm2,%%xmm1;"
+ "or %12,%10;"
+ "add %10,%9;"
+ "movdqa %%xmm3,%%xmm2;"
+ "mov %6,%10;"
+ "mov %9,%11;"
+ "movdqa %%xmm3,%%xmm8;"
+ "ror $0xe,%10;"
+ "xor %6,%10;"
+ "mov %k2,%12;"
+ "ror $0x9,%11;"
+ "pslld $0xe,%%xmm3;"
+ "xor %9,%11;"
+ "ror $0x5,%10;"
+ "xor %7,%12;"
+ "psrld $0x12,%%xmm2;"
+ "ror $0xb,%11;"
+ "xor %6,%10;"
+ "and %6,%12;"
+ "ror $0x6,%10;"
+ "pxor %%xmm3,%%xmm1;"
+ "xor %9,%11;"
+ "xor %7,%12;"
+ "psrld $0x3,%%xmm8;"
+ "add %10,%12;"
+ "add 4+%16,%12;"
+ "ror $0x2,%11;"
+ "pxor %%xmm2,%%xmm1;"
+ "mov %9,%10;"
+ "add %12,%8;"
+ "mov %9,%12;"
+ "pxor %%xmm8,%%xmm1;"
+ "or %4,%10;"
+ "add %8,%5;"
+ "and %4,%12;"
+ "pshufd $0xfa,%%xmm5,%%xmm2;"
+ "and %3,%10;"
+ "add %11,%8;"
+ "paddd %%xmm1,%%xmm0;"
+ "or %12,%10;"
+ "add %10,%8;"
+ "movdqa %%xmm2,%%xmm3;"
+ "mov %5,%10;"
+ "mov %8,%11;"
+ "ror $0xe,%10;"
+ "movdqa %%xmm2,%%xmm8;"
+ "xor %5,%10;"
+ "ror $0x9,%11;"
+ "mov %6,%12;"
+ "xor %8,%11;"
+ "ror $0x5,%10;"
+ "psrlq $0x11,%%xmm2;"
+ "xor %k2,%12;"
+ "psrlq $0x13,%%xmm3;"
+ "xor %5,%10;"
+ "and %5,%12;"
+ "psrld $0xa,%%xmm8;"
+ "ror $0xb,%11;"
+ "xor %8,%11;"
+ "xor %k2,%12;"
+ "ror $0x6,%10;"
+ "pxor %%xmm3,%%xmm2;"
+ "add %10,%12;"
+ "ror $0x2,%11;"
+ "add 8+%16,%12;"
+ "pxor %%xmm2,%%xmm8;"
+ "mov %8,%10;"
+ "add %12,%7;"
+ "mov %8,%12;"
+ "pshufb %%xmm10,%%xmm8;"
+ "or %3,%10;"
+ "add %7,%4;"
+ "and %3,%12;"
+ "paddd %%xmm8,%%xmm0;"
+ "and %9,%10;"
+ "add %11,%7;"
+ "pshufd $0x50,%%xmm0,%%xmm2;"
+ "or %12,%10;"
+ "add %10,%7;"
+ "movdqa %%xmm2,%%xmm3;"
+ "mov %4,%10;"
+ "ror $0xe,%10;"
+ "mov %7,%11;"
+ "movdqa %%xmm2,%%xmm6;"
+ "ror $0x9,%11;"
+ "xor %4,%10;"
+ "mov %5,%12;"
+ "ror $0x5,%10;"
+ "psrlq $0x11,%%xmm2;"
+ "xor %7,%11;"
+ "xor %6,%12;"
+ "psrlq $0x13,%%xmm3;"
+ "xor %4,%10;"
+ "and %4,%12;"
+ "ror $0xb,%11;"
+ "psrld $0xa,%%xmm6;"
+ "xor %7,%11;"
+ "ror $0x6,%10;"
+ "xor %6,%12;"
+ "pxor %%xmm3,%%xmm2;"
+ "ror $0x2,%11;"
+ "add %10,%12;"
+ "add 12+%16,%12;"
+ "pxor %%xmm2,%%xmm6;"
+ "mov %7,%10;"
+ "add %12,%k2;"
+ "mov %7,%12;"
+ "pshufb %%xmm11,%%xmm6;"
+ "or %9,%10;"
+ "add %k2,%3;"
+ "and %9,%12;"
+ "paddd %%xmm0,%%xmm6;"
+ "and %8,%10;"
+ "add %11,%k2;"
+ "or %12,%10;"
+ "add %10,%k2;"
+ "movdqa 0x30(%13),%%xmm9;"
+ "paddd %%xmm7,%%xmm9;"
+ "movdqa %%xmm9,%16;"
+ "add $0x40,%13;"
+ "movdqa %%xmm6,%%xmm0;"
+ "mov %3,%10;"
+ "ror $0xe,%10;"
+ "mov %k2,%11;"
+ "palignr $0x4,%%xmm5,%%xmm0;"
+ "ror $0x9,%11;"
+ "xor %3,%10;"
+ "mov %4,%12;"
+ "ror $0x5,%10;"
+ "movdqa %%xmm4,%%xmm1;"
+ "xor %k2,%11;"
+ "xor %5,%12;"
+ "paddd %%xmm7,%%xmm0;"
+ "xor %3,%10;"
+ "and %3,%12;"
+ "ror $0xb,%11;"
+ "palignr $0x4,%%xmm7,%%xmm1;"
+ "xor %k2,%11;"
+ "ror $0x6,%10;"
+ "xor %5,%12;"
+ "movdqa %%xmm1,%%xmm2;"
+ "ror $0x2,%11;"
+ "add %10,%12;"
+ "add %16,%12;"
+ "movdqa %%xmm1,%%xmm3;"
+ "mov %k2,%10;"
+ "add %12,%6;"
+ "mov %k2,%12;"
+ "pslld $0x19,%%xmm1;"
+ "or %8,%10;"
+ "add %6,%9;"
+ "and %8,%12;"
+ "psrld $0x7,%%xmm2;"
+ "and %7,%10;"
+ "add %11,%6;"
+ "por %%xmm2,%%xmm1;"
+ "or %12,%10;"
+ "add %10,%6;"
+ "movdqa %%xmm3,%%xmm2;"
+ "mov %9,%10;"
+ "mov %6,%11;"
+ "movdqa %%xmm3,%%xmm8;"
+ "ror $0xe,%10;"
+ "xor %9,%10;"
+ "mov %3,%12;"
+ "ror $0x9,%11;"
+ "pslld $0xe,%%xmm3;"
+ "xor %6,%11;"
+ "ror $0x5,%10;"
+ "xor %4,%12;"
+ "psrld $0x12,%%xmm2;"
+ "ror $0xb,%11;"
+ "xor %9,%10;"
+ "and %9,%12;"
+ "ror $0x6,%10;"
+ "pxor %%xmm3,%%xmm1;"
+ "xor %6,%11;"
+ "xor %4,%12;"
+ "psrld $0x3,%%xmm8;"
+ "add %10,%12;"
+ "add 4+%16,%12;"
+ "ror $0x2,%11;"
+ "pxor %%xmm2,%%xmm1;"
+ "mov %6,%10;"
+ "add %12,%5;"
+ "mov %6,%12;"
+ "pxor %%xmm8,%%xmm1;"
+ "or %7,%10;"
+ "add %5,%8;"
+ "and %7,%12;"
+ "pshufd $0xfa,%%xmm6,%%xmm2;"
+ "and %k2,%10;"
+ "add %11,%5;"
+ "paddd %%xmm1,%%xmm0;"
+ "or %12,%10;"
+ "add %10,%5;"
+ "movdqa %%xmm2,%%xmm3;"
+ "mov %8,%10;"
+ "mov %5,%11;"
+ "ror $0xe,%10;"
+ "movdqa %%xmm2,%%xmm8;"
+ "xor %8,%10;"
+ "ror $0x9,%11;"
+ "mov %9,%12;"
+ "xor %5,%11;"
+ "ror $0x5,%10;"
+ "psrlq $0x11,%%xmm2;"
+ "xor %3,%12;"
+ "psrlq $0x13,%%xmm3;"
+ "xor %8,%10;"
+ "and %8,%12;"
+ "psrld $0xa,%%xmm8;"
+ "ror $0xb,%11;"
+ "xor %5,%11;"
+ "xor %3,%12;"
+ "ror $0x6,%10;"
+ "pxor %%xmm3,%%xmm2;"
+ "add %10,%12;"
+ "ror $0x2,%11;"
+ "add 8+%16,%12;"
+ "pxor %%xmm2,%%xmm8;"
+ "mov %5,%10;"
+ "add %12,%4;"
+ "mov %5,%12;"
+ "pshufb %%xmm10,%%xmm8;"
+ "or %k2,%10;"
+ "add %4,%7;"
+ "and %k2,%12;"
+ "paddd %%xmm8,%%xmm0;"
+ "and %6,%10;"
+ "add %11,%4;"
+ "pshufd $0x50,%%xmm0,%%xmm2;"
+ "or %12,%10;"
+ "add %10,%4;"
+ "movdqa %%xmm2,%%xmm3;"
+ "mov %7,%10;"
+ "ror $0xe,%10;"
+ "mov %4,%11;"
+ "movdqa %%xmm2,%%xmm7;"
+ "ror $0x9,%11;"
+ "xor %7,%10;"
+ "mov %8,%12;"
+ "ror $0x5,%10;"
+ "psrlq $0x11,%%xmm2;"
+ "xor %4,%11;"
+ "xor %9,%12;"
+ "psrlq $0x13,%%xmm3;"
+ "xor %7,%10;"
+ "and %7,%12;"
+ "ror $0xb,%11;"
+ "psrld $0xa,%%xmm7;"
+ "xor %4,%11;"
+ "ror $0x6,%10;"
+ "xor %9,%12;"
+ "pxor %%xmm3,%%xmm2;"
+ "ror $0x2,%11;"
+ "add %10,%12;"
+ "add 12+%16,%12;"
+ "pxor %%xmm2,%%xmm7;"
+ "mov %4,%10;"
+ "add %12,%3;"
+ "mov %4,%12;"
+ "pshufb %%xmm11,%%xmm7;"
+ "or %6,%10;"
+ "add %3,%k2;"
+ "and %6,%12;"
+ "paddd %%xmm0,%%xmm7;"
+ "and %5,%10;"
+ "add %11,%3;"
+ "or %12,%10;"
+ "add %10,%3;"
+ "sub $0x1,%1;"
+ "jne Lloop1_%=;"
+ "mov $0x2,%1;"
+
+ "Lloop2_%=:"
+ "paddd 0x0(%13),%%xmm4;"
+ "movdqa %%xmm4,%16;"
+ "mov %k2,%10;"
+ "ror $0xe,%10;"
+ "mov %3,%11;"
+ "xor %k2,%10;"
+ "ror $0x9,%11;"
+ "mov %7,%12;"
+ "xor %3,%11;"
+ "ror $0x5,%10;"
+ "xor %8,%12;"
+ "xor %k2,%10;"
+ "ror $0xb,%11;"
+ "and %k2,%12;"
+ "xor %3,%11;"
+ "ror $0x6,%10;"
+ "xor %8,%12;"
+ "add %10,%12;"
+ "ror $0x2,%11;"
+ "add %16,%12;"
+ "mov %3,%10;"
+ "add %12,%9;"
+ "mov %3,%12;"
+ "or %5,%10;"
+ "add %9,%6;"
+ "and %5,%12;"
+ "and %4,%10;"
+ "add %11,%9;"
+ "or %12,%10;"
+ "add %10,%9;"
+ "mov %6,%10;"
+ "ror $0xe,%10;"
+ "mov %9,%11;"
+ "xor %6,%10;"
+ "ror $0x9,%11;"
+ "mov %k2,%12;"
+ "xor %9,%11;"
+ "ror $0x5,%10;"
+ "xor %7,%12;"
+ "xor %6,%10;"
+ "ror $0xb,%11;"
+ "and %6,%12;"
+ "xor %9,%11;"
+ "ror $0x6,%10;"
+ "xor %7,%12;"
+ "add %10,%12;"
+ "ror $0x2,%11;"
+ "add 4+%16,%12;"
+ "mov %9,%10;"
+ "add %12,%8;"
+ "mov %9,%12;"
+ "or %4,%10;"
+ "add %8,%5;"
+ "and %4,%12;"
+ "and %3,%10;"
+ "add %11,%8;"
+ "or %12,%10;"
+ "add %10,%8;"
+ "mov %5,%10;"
+ "ror $0xe,%10;"
+ "mov %8,%11;"
+ "xor %5,%10;"
+ "ror $0x9,%11;"
+ "mov %6,%12;"
+ "xor %8,%11;"
+ "ror $0x5,%10;"
+ "xor %k2,%12;"
+ "xor %5,%10;"
+ "ror $0xb,%11;"
+ "and %5,%12;"
+ "xor %8,%11;"
+ "ror $0x6,%10;"
+ "xor %k2,%12;"
+ "add %10,%12;"
+ "ror $0x2,%11;"
+ "add 8+%16,%12;"
+ "mov %8,%10;"
+ "add %12,%7;"
+ "mov %8,%12;"
+ "or %3,%10;"
+ "add %7,%4;"
+ "and %3,%12;"
+ "and %9,%10;"
+ "add %11,%7;"
+ "or %12,%10;"
+ "add %10,%7;"
+ "mov %4,%10;"
+ "ror $0xe,%10;"
+ "mov %7,%11;"
+ "xor %4,%10;"
+ "ror $0x9,%11;"
+ "mov %5,%12;"
+ "xor %7,%11;"
+ "ror $0x5,%10;"
+ "xor %6,%12;"
+ "xor %4,%10;"
+ "ror $0xb,%11;"
+ "and %4,%12;"
+ "xor %7,%11;"
+ "ror $0x6,%10;"
+ "xor %6,%12;"
+ "add %10,%12;"
+ "ror $0x2,%11;"
+ "add 12+%16,%12;"
+ "mov %7,%10;"
+ "add %12,%k2;"
+ "mov %7,%12;"
+ "or %9,%10;"
+ "add %k2,%3;"
+ "and %9,%12;"
+ "and %8,%10;"
+ "add %11,%k2;"
+ "or %12,%10;"
+ "add %10,%k2;"
+ "paddd 0x10(%13),%%xmm5;"
+ "movdqa %%xmm5,%16;"
+ "add $0x20,%13;"
+ "mov %3,%10;"
+ "ror $0xe,%10;"
+ "mov %k2,%11;"
+ "xor %3,%10;"
+ "ror $0x9,%11;"
+ "mov %4,%12;"
+ "xor %k2,%11;"
+ "ror $0x5,%10;"
+ "xor %5,%12;"
+ "xor %3,%10;"
+ "ror $0xb,%11;"
+ "and %3,%12;"
+ "xor %k2,%11;"
+ "ror $0x6,%10;"
+ "xor %5,%12;"
+ "add %10,%12;"
+ "ror $0x2,%11;"
+ "add %16,%12;"
+ "mov %k2,%10;"
+ "add %12,%6;"
+ "mov %k2,%12;"
+ "or %8,%10;"
+ "add %6,%9;"
+ "and %8,%12;"
+ "and %7,%10;"
+ "add %11,%6;"
+ "or %12,%10;"
+ "add %10,%6;"
+ "mov %9,%10;"
+ "ror $0xe,%10;"
+ "mov %6,%11;"
+ "xor %9,%10;"
+ "ror $0x9,%11;"
+ "mov %3,%12;"
+ "xor %6,%11;"
+ "ror $0x5,%10;"
+ "xor %4,%12;"
+ "xor %9,%10;"
+ "ror $0xb,%11;"
+ "and %9,%12;"
+ "xor %6,%11;"
+ "ror $0x6,%10;"
+ "xor %4,%12;"
+ "add %10,%12;"
+ "ror $0x2,%11;"
+ "add 4+%16,%12;"
+ "mov %6,%10;"
+ "add %12,%5;"
+ "mov %6,%12;"
+ "or %7,%10;"
+ "add %5,%8;"
+ "and %7,%12;"
+ "and %k2,%10;"
+ "add %11,%5;"
+ "or %12,%10;"
+ "add %10,%5;"
+ "mov %8,%10;"
+ "ror $0xe,%10;"
+ "mov %5,%11;"
+ "xor %8,%10;"
+ "ror $0x9,%11;"
+ "mov %9,%12;"
+ "xor %5,%11;"
+ "ror $0x5,%10;"
+ "xor %3,%12;"
+ "xor %8,%10;"
+ "ror $0xb,%11;"
+ "and %8,%12;"
+ "xor %5,%11;"
+ "ror $0x6,%10;"
+ "xor %3,%12;"
+ "add %10,%12;"
+ "ror $0x2,%11;"
+ "add 8+%16,%12;"
+ "mov %5,%10;"
+ "add %12,%4;"
+ "mov %5,%12;"
+ "or %k2,%10;"
+ "add %4,%7;"
+ "and %k2,%12;"
+ "and %6,%10;"
+ "add %11,%4;"
+ "or %12,%10;"
+ "add %10,%4;"
+ "mov %7,%10;"
+ "ror $0xe,%10;"
+ "mov %4,%11;"
+ "xor %7,%10;"
+ "ror $0x9,%11;"
+ "mov %8,%12;"
+ "xor %4,%11;"
+ "ror $0x5,%10;"
+ "xor %9,%12;"
+ "xor %7,%10;"
+ "ror $0xb,%11;"
+ "and %7,%12;"
+ "xor %4,%11;"
+ "ror $0x6,%10;"
+ "xor %9,%12;"
+ "add %10,%12;"
+ "ror $0x2,%11;"
+ "add 12+%16,%12;"
+ "mov %4,%10;"
+ "add %12,%3;"
+ "mov %4,%12;"
+ "or %6,%10;"
+ "add %3,%k2;"
+ "and %6,%12;"
+ "and %5,%10;"
+ "add %11,%3;"
+ "or %12,%10;"
+ "add %10,%3;"
+ "movdqa %%xmm6,%%xmm4;"
+ "movdqa %%xmm7,%%xmm5;"
+ "sub $0x1,%1;"
+ "jne Lloop2_%=;"
+ "add (%0),%3;"
+ "mov %3,(%0);"
+ "add 0x4(%0),%4;"
+ "mov %4,0x4(%0);"
+ "add 0x8(%0),%5;"
+ "mov %5,0x8(%0);"
+ "add 0xc(%0),%6;"
+ "mov %6,0xc(%0);"
+ "add 0x10(%0),%k2;"
+ "mov %k2,0x10(%0);"
+ "add 0x14(%0),%7;"
+ "mov %7,0x14(%0);"
+ "add 0x18(%0),%8;"
+ "mov %8,0x18(%0);"
+ "add 0x1c(%0),%9;"
+ "mov %9,0x1c(%0);"
+ "mov %15,%1;"
+ "add $0x40,%1;"
+ "cmp %14,%1;"
+ "jne Lloop0_%=;"
+
+ "Ldone_hash_%=:"
+
+ : "+r"(s), "+r"(chunk), "+r"(blocks), "=r"(a), "=r"(b), "=r"(c), "=r"(d), /* e = chunk */ "=r"(f), "=r"(g), "=r"(h), "=r"(y0), "=r"(y1), "=r"(y2), "=r"(tbl), "+m"(inp_end), "+m"(inp), "+m"(xfer)
+ : "m"(K256), "m"(FLIP_MASK), "m"(SHUF_00BA), "m"(SHUF_DC00)
+ : "cc", "memory", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11", "xmm12"
+ );
+}
+}
+
+/*
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright (c) 2012, Intel Corporation
+;
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are
+; met:
+;
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+;
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in the
+; documentation and/or other materials provided with the
+; distribution.
+;
+; * Neither the name of the Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived from
+; this software without specific prior written permission.
+;
+;
+; THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" AND ANY
+; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+; PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR
+; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Example YASM command lines:
+; Windows: yasm -Xvc -f x64 -rnasm -pnasm -o sha256_sse4.obj -g cv8 sha256_sse4.asm
+; Linux: yasm -f x64 -f elf64 -X gnu -g dwarf2 -D LINUX -o sha256_sse4.o sha256_sse4.asm
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; This code is described in an Intel White-Paper:
+; "Fast SHA-256 Implementations on Intel Architecture Processors"
+;
+; To find it, surf to http://www.intel.com/p/en_US/embedded
+; and search for that title.
+; The paper is expected to be released roughly at the end of April, 2012
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; This code schedules 1 blocks at a time, with 4 lanes per block
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+%define MOVDQ movdqu ;; assume buffers not aligned
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Define Macros
+
+; addm [mem], reg
+; Add reg to mem using reg-mem add and store
+%macro addm 2
+ add %2, %1
+ mov %1, %2
+%endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; COPY_XMM_AND_BSWAP xmm, [mem], byte_flip_mask
+; Load xmm with mem and byte swap each dword
+%macro COPY_XMM_AND_BSWAP 3
+ MOVDQ %1, %2
+ pshufb %1, %3
+%endmacro
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+%define X0 xmm4
+%define X1 xmm5
+%define X2 xmm6
+%define X3 xmm7
+
+%define XTMP0 xmm0
+%define XTMP1 xmm1
+%define XTMP2 xmm2
+%define XTMP3 xmm3
+%define XTMP4 xmm8
+%define XFER xmm9
+
+%define SHUF_00BA xmm10 ; shuffle xBxA -> 00BA
+%define SHUF_DC00 xmm11 ; shuffle xDxC -> DC00
+%define BYTE_FLIP_MASK xmm12
+
+%ifdef LINUX
+%define NUM_BLKS rdx ; 3rd arg
+%define CTX rsi ; 2nd arg
+%define INP rdi ; 1st arg
+
+%define SRND rdi ; clobbers INP
+%define c ecx
+%define d r8d
+%define e edx
+%else
+%define NUM_BLKS r8 ; 3rd arg
+%define CTX rdx ; 2nd arg
+%define INP rcx ; 1st arg
+
+%define SRND rcx ; clobbers INP
+%define c edi
+%define d esi
+%define e r8d
+
+%endif
+%define TBL rbp
+%define a eax
+%define b ebx
+
+%define f r9d
+%define g r10d
+%define h r11d
+
+%define y0 r13d
+%define y1 r14d
+%define y2 r15d
+
+
+
+_INP_END_SIZE equ 8
+_INP_SIZE equ 8
+_XFER_SIZE equ 8
+%ifdef LINUX
+_XMM_SAVE_SIZE equ 0
+%else
+_XMM_SAVE_SIZE equ 7*16
+%endif
+; STACK_SIZE plus pushes must be an odd multiple of 8
+_ALIGN_SIZE equ 8
+
+_INP_END equ 0
+_INP equ _INP_END + _INP_END_SIZE
+_XFER equ _INP + _INP_SIZE
+_XMM_SAVE equ _XFER + _XFER_SIZE + _ALIGN_SIZE
+STACK_SIZE equ _XMM_SAVE + _XMM_SAVE_SIZE
+
+; rotate_Xs
+; Rotate values of symbols X0...X3
+%macro rotate_Xs 0
+%xdefine X_ X0
+%xdefine X0 X1
+%xdefine X1 X2
+%xdefine X2 X3
+%xdefine X3 X_
+%endm
+
+; ROTATE_ARGS
+; Rotate values of symbols a...h
+%macro ROTATE_ARGS 0
+%xdefine TMP_ h
+%xdefine h g
+%xdefine g f
+%xdefine f e
+%xdefine e d
+%xdefine d c
+%xdefine c b
+%xdefine b a
+%xdefine a TMP_
+%endm
+
+%macro FOUR_ROUNDS_AND_SCHED 0
+ ;; compute s0 four at a time and s1 two at a time
+ ;; compute W[-16] + W[-7] 4 at a time
+ movdqa XTMP0, X3
+ mov y0, e ; y0 = e
+ ror y0, (25-11) ; y0 = e >> (25-11)
+ mov y1, a ; y1 = a
+ palignr XTMP0, X2, 4 ; XTMP0 = W[-7]
+ ror y1, (22-13) ; y1 = a >> (22-13)
+ xor y0, e ; y0 = e ^ (e >> (25-11))
+ mov y2, f ; y2 = f
+ ror y0, (11-6) ; y0 = (e >> (11-6)) ^ (e >> (25-6))
+ movdqa XTMP1, X1
+ xor y1, a ; y1 = a ^ (a >> (22-13)
+ xor y2, g ; y2 = f^g
+ paddd XTMP0, X0 ; XTMP0 = W[-7] + W[-16]
+ xor y0, e ; y0 = e ^ (e >> (11-6)) ^ (e >> (25-6))
+ and y2, e ; y2 = (f^g)&e
+ ror y1, (13-2) ; y1 = (a >> (13-2)) ^ (a >> (22-2))
+ ;; compute s0
+ palignr XTMP1, X0, 4 ; XTMP1 = W[-15]
+ xor y1, a ; y1 = a ^ (a >> (13-2)) ^ (a >> (22-2))
+ ror y0, 6 ; y0 = S1 = (e>>6) & (e>>11) ^ (e>>25)
+ xor y2, g ; y2 = CH = ((f^g)&e)^g
+ movdqa XTMP2, XTMP1 ; XTMP2 = W[-15]
+ ror y1, 2 ; y1 = S0 = (a>>2) ^ (a>>13) ^ (a>>22)
+ add y2, y0 ; y2 = S1 + CH
+ add y2, [rsp + _XFER + 0*4] ; y2 = k + w + S1 + CH
+ movdqa XTMP3, XTMP1 ; XTMP3 = W[-15]
+ mov y0, a ; y0 = a
+ add h, y2 ; h = h + S1 + CH + k + w
+ mov y2, a ; y2 = a
+ pslld XTMP1, (32-7)
+ or y0, c ; y0 = a|c
+ add d, h ; d = d + h + S1 + CH + k + w
+ and y2, c ; y2 = a&c
+ psrld XTMP2, 7
+ and y0, b ; y0 = (a|c)&b
+ add h, y1 ; h = h + S1 + CH + k + w + S0
+ por XTMP1, XTMP2 ; XTMP1 = W[-15] ror 7
+ or y0, y2 ; y0 = MAJ = (a|c)&b)|(a&c)
+ add h, y0 ; h = h + S1 + CH + k + w + S0 + MAJ
+
+ROTATE_ARGS
+ movdqa XTMP2, XTMP3 ; XTMP2 = W[-15]
+ mov y0, e ; y0 = e
+ mov y1, a ; y1 = a
+ movdqa XTMP4, XTMP3 ; XTMP4 = W[-15]
+ ror y0, (25-11) ; y0 = e >> (25-11)
+ xor y0, e ; y0 = e ^ (e >> (25-11))
+ mov y2, f ; y2 = f
+ ror y1, (22-13) ; y1 = a >> (22-13)
+ pslld XTMP3, (32-18)
+ xor y1, a ; y1 = a ^ (a >> (22-13)
+ ror y0, (11-6) ; y0 = (e >> (11-6)) ^ (e >> (25-6))
+ xor y2, g ; y2 = f^g
+ psrld XTMP2, 18
+ ror y1, (13-2) ; y1 = (a >> (13-2)) ^ (a >> (22-2))
+ xor y0, e ; y0 = e ^ (e >> (11-6)) ^ (e >> (25-6))
+ and y2, e ; y2 = (f^g)&e
+ ror y0, 6 ; y0 = S1 = (e>>6) & (e>>11) ^ (e>>25)
+ pxor XTMP1, XTMP3
+ xor y1, a ; y1 = a ^ (a >> (13-2)) ^ (a >> (22-2))
+ xor y2, g ; y2 = CH = ((f^g)&e)^g
+ psrld XTMP4, 3 ; XTMP4 = W[-15] >> 3
+ add y2, y0 ; y2 = S1 + CH
+ add y2, [rsp + _XFER + 1*4] ; y2 = k + w + S1 + CH
+ ror y1, 2 ; y1 = S0 = (a>>2) ^ (a>>13) ^ (a>>22)
+ pxor XTMP1, XTMP2 ; XTMP1 = W[-15] ror 7 ^ W[-15] ror 18
+ mov y0, a ; y0 = a
+ add h, y2 ; h = h + S1 + CH + k + w
+ mov y2, a ; y2 = a
+ pxor XTMP1, XTMP4 ; XTMP1 = s0
+ or y0, c ; y0 = a|c
+ add d, h ; d = d + h + S1 + CH + k + w
+ and y2, c ; y2 = a&c
+ ;; compute low s1
+ pshufd XTMP2, X3, 11111010b ; XTMP2 = W[-2] {BBAA}
+ and y0, b ; y0 = (a|c)&b
+ add h, y1 ; h = h + S1 + CH + k + w + S0
+ paddd XTMP0, XTMP1 ; XTMP0 = W[-16] + W[-7] + s0
+ or y0, y2 ; y0 = MAJ = (a|c)&b)|(a&c)
+ add h, y0 ; h = h + S1 + CH + k + w + S0 + MAJ
+
+ROTATE_ARGS
+ movdqa XTMP3, XTMP2 ; XTMP3 = W[-2] {BBAA}
+ mov y0, e ; y0 = e
+ mov y1, a ; y1 = a
+ ror y0, (25-11) ; y0 = e >> (25-11)
+ movdqa XTMP4, XTMP2 ; XTMP4 = W[-2] {BBAA}
+ xor y0, e ; y0 = e ^ (e >> (25-11))
+ ror y1, (22-13) ; y1 = a >> (22-13)
+ mov y2, f ; y2 = f
+ xor y1, a ; y1 = a ^ (a >> (22-13)
+ ror y0, (11-6) ; y0 = (e >> (11-6)) ^ (e >> (25-6))
+ psrlq XTMP2, 17 ; XTMP2 = W[-2] ror 17 {xBxA}
+ xor y2, g ; y2 = f^g
+ psrlq XTMP3, 19 ; XTMP3 = W[-2] ror 19 {xBxA}
+ xor y0, e ; y0 = e ^ (e >> (11-6)) ^ (e >> (25-6))
+ and y2, e ; y2 = (f^g)&e
+ psrld XTMP4, 10 ; XTMP4 = W[-2] >> 10 {BBAA}
+ ror y1, (13-2) ; y1 = (a >> (13-2)) ^ (a >> (22-2))
+ xor y1, a ; y1 = a ^ (a >> (13-2)) ^ (a >> (22-2))
+ xor y2, g ; y2 = CH = ((f^g)&e)^g
+ ror y0, 6 ; y0 = S1 = (e>>6) & (e>>11) ^ (e>>25)
+ pxor XTMP2, XTMP3
+ add y2, y0 ; y2 = S1 + CH
+ ror y1, 2 ; y1 = S0 = (a>>2) ^ (a>>13) ^ (a>>22)
+ add y2, [rsp + _XFER + 2*4] ; y2 = k + w + S1 + CH
+ pxor XTMP4, XTMP2 ; XTMP4 = s1 {xBxA}
+ mov y0, a ; y0 = a
+ add h, y2 ; h = h + S1 + CH + k + w
+ mov y2, a ; y2 = a
+ pshufb XTMP4, SHUF_00BA ; XTMP4 = s1 {00BA}
+ or y0, c ; y0 = a|c
+ add d, h ; d = d + h + S1 + CH + k + w
+ and y2, c ; y2 = a&c
+ paddd XTMP0, XTMP4 ; XTMP0 = {..., ..., W[1], W[0]}
+ and y0, b ; y0 = (a|c)&b
+ add h, y1 ; h = h + S1 + CH + k + w + S0
+ ;; compute high s1
+ pshufd XTMP2, XTMP0, 01010000b ; XTMP2 = W[-2] {DDCC}
+ or y0, y2 ; y0 = MAJ = (a|c)&b)|(a&c)
+ add h, y0 ; h = h + S1 + CH + k + w + S0 + MAJ
+
+ROTATE_ARGS
+ movdqa XTMP3, XTMP2 ; XTMP3 = W[-2] {DDCC}
+ mov y0, e ; y0 = e
+ ror y0, (25-11) ; y0 = e >> (25-11)
+ mov y1, a ; y1 = a
+ movdqa X0, XTMP2 ; X0 = W[-2] {DDCC}
+ ror y1, (22-13) ; y1 = a >> (22-13)
+ xor y0, e ; y0 = e ^ (e >> (25-11))
+ mov y2, f ; y2 = f
+ ror y0, (11-6) ; y0 = (e >> (11-6)) ^ (e >> (25-6))
+ psrlq XTMP2, 17 ; XTMP2 = W[-2] ror 17 {xDxC}
+ xor y1, a ; y1 = a ^ (a >> (22-13)
+ xor y2, g ; y2 = f^g
+ psrlq XTMP3, 19 ; XTMP3 = W[-2] ror 19 {xDxC}
+ xor y0, e ; y0 = e ^ (e >> (11-6)) ^ (e >> (25-6))
+ and y2, e ; y2 = (f^g)&e
+ ror y1, (13-2) ; y1 = (a >> (13-2)) ^ (a >> (22-2))
+ psrld X0, 10 ; X0 = W[-2] >> 10 {DDCC}
+ xor y1, a ; y1 = a ^ (a >> (13-2)) ^ (a >> (22-2))
+ ror y0, 6 ; y0 = S1 = (e>>6) & (e>>11) ^ (e>>25)
+ xor y2, g ; y2 = CH = ((f^g)&e)^g
+ pxor XTMP2, XTMP3
+ ror y1, 2 ; y1 = S0 = (a>>2) ^ (a>>13) ^ (a>>22)
+ add y2, y0 ; y2 = S1 + CH
+ add y2, [rsp + _XFER + 3*4] ; y2 = k + w + S1 + CH
+ pxor X0, XTMP2 ; X0 = s1 {xDxC}
+ mov y0, a ; y0 = a
+ add h, y2 ; h = h + S1 + CH + k + w
+ mov y2, a ; y2 = a
+ pshufb X0, SHUF_DC00 ; X0 = s1 {DC00}
+ or y0, c ; y0 = a|c
+ add d, h ; d = d + h + S1 + CH + k + w
+ and y2, c ; y2 = a&c
+ paddd X0, XTMP0 ; X0 = {W[3], W[2], W[1], W[0]}
+ and y0, b ; y0 = (a|c)&b
+ add h, y1 ; h = h + S1 + CH + k + w + S0
+ or y0, y2 ; y0 = MAJ = (a|c)&b)|(a&c)
+ add h, y0 ; h = h + S1 + CH + k + w + S0 + MAJ
+
+ROTATE_ARGS
+rotate_Xs
+%endm
+
+;; input is [rsp + _XFER + %1 * 4]
+%macro DO_ROUND 1
+ mov y0, e ; y0 = e
+ ror y0, (25-11) ; y0 = e >> (25-11)
+ mov y1, a ; y1 = a
+ xor y0, e ; y0 = e ^ (e >> (25-11))
+ ror y1, (22-13) ; y1 = a >> (22-13)
+ mov y2, f ; y2 = f
+ xor y1, a ; y1 = a ^ (a >> (22-13)
+ ror y0, (11-6) ; y0 = (e >> (11-6)) ^ (e >> (25-6))
+ xor y2, g ; y2 = f^g
+ xor y0, e ; y0 = e ^ (e >> (11-6)) ^ (e >> (25-6))
+ ror y1, (13-2) ; y1 = (a >> (13-2)) ^ (a >> (22-2))
+ and y2, e ; y2 = (f^g)&e
+ xor y1, a ; y1 = a ^ (a >> (13-2)) ^ (a >> (22-2))
+ ror y0, 6 ; y0 = S1 = (e>>6) & (e>>11) ^ (e>>25)
+ xor y2, g ; y2 = CH = ((f^g)&e)^g
+ add y2, y0 ; y2 = S1 + CH
+ ror y1, 2 ; y1 = S0 = (a>>2) ^ (a>>13) ^ (a>>22)
+ add y2, [rsp + _XFER + %1 * 4] ; y2 = k + w + S1 + CH
+ mov y0, a ; y0 = a
+ add h, y2 ; h = h + S1 + CH + k + w
+ mov y2, a ; y2 = a
+ or y0, c ; y0 = a|c
+ add d, h ; d = d + h + S1 + CH + k + w
+ and y2, c ; y2 = a&c
+ and y0, b ; y0 = (a|c)&b
+ add h, y1 ; h = h + S1 + CH + k + w + S0
+ or y0, y2 ; y0 = MAJ = (a|c)&b)|(a&c)
+ add h, y0 ; h = h + S1 + CH + k + w + S0 + MAJ
+ ROTATE_ARGS
+%endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; void sha256_sse4(void *input_data, UINT32 digest[8], UINT64 num_blks)
+;; arg 1 : pointer to input data
+;; arg 2 : pointer to digest
+;; arg 3 : Num blocks
+section .text
+global sha256_sse4
+align 32
+sha256_sse4:
+ push rbx
+%ifndef LINUX
+ push rsi
+ push rdi
+%endif
+ push rbp
+ push r13
+ push r14
+ push r15
+
+ sub rsp,STACK_SIZE
+%ifndef LINUX
+ movdqa [rsp + _XMM_SAVE + 0*16],xmm6
+ movdqa [rsp + _XMM_SAVE + 1*16],xmm7
+ movdqa [rsp + _XMM_SAVE + 2*16],xmm8
+ movdqa [rsp + _XMM_SAVE + 3*16],xmm9
+ movdqa [rsp + _XMM_SAVE + 4*16],xmm10
+ movdqa [rsp + _XMM_SAVE + 5*16],xmm11
+ movdqa [rsp + _XMM_SAVE + 6*16],xmm12
+%endif
+
+ shl NUM_BLKS, 6 ; convert to bytes
+ jz done_hash
+ add NUM_BLKS, INP ; pointer to end of data
+ mov [rsp + _INP_END], NUM_BLKS
+
+ ;; load initial digest
+ mov a,[4*0 + CTX]
+ mov b,[4*1 + CTX]
+ mov c,[4*2 + CTX]
+ mov d,[4*3 + CTX]
+ mov e,[4*4 + CTX]
+ mov f,[4*5 + CTX]
+ mov g,[4*6 + CTX]
+ mov h,[4*7 + CTX]
+
+ movdqa BYTE_FLIP_MASK, [PSHUFFLE_BYTE_FLIP_MASK wrt rip]
+ movdqa SHUF_00BA, [_SHUF_00BA wrt rip]
+ movdqa SHUF_DC00, [_SHUF_DC00 wrt rip]
+
+loop0:
+ lea TBL,[K256 wrt rip]
+
+ ;; byte swap first 16 dwords
+ COPY_XMM_AND_BSWAP X0, [INP + 0*16], BYTE_FLIP_MASK
+ COPY_XMM_AND_BSWAP X1, [INP + 1*16], BYTE_FLIP_MASK
+ COPY_XMM_AND_BSWAP X2, [INP + 2*16], BYTE_FLIP_MASK
+ COPY_XMM_AND_BSWAP X3, [INP + 3*16], BYTE_FLIP_MASK
+
+ mov [rsp + _INP], INP
+
+ ;; schedule 48 input dwords, by doing 3 rounds of 16 each
+ mov SRND, 3
+align 16
+loop1:
+ movdqa XFER, [TBL + 0*16]
+ paddd XFER, X0
+ movdqa [rsp + _XFER], XFER
+ FOUR_ROUNDS_AND_SCHED
+
+ movdqa XFER, [TBL + 1*16]
+ paddd XFER, X0
+ movdqa [rsp + _XFER], XFER
+ FOUR_ROUNDS_AND_SCHED
+
+ movdqa XFER, [TBL + 2*16]
+ paddd XFER, X0
+ movdqa [rsp + _XFER], XFER
+ FOUR_ROUNDS_AND_SCHED
+
+ movdqa XFER, [TBL + 3*16]
+ paddd XFER, X0
+ movdqa [rsp + _XFER], XFER
+ add TBL, 4*16
+ FOUR_ROUNDS_AND_SCHED
+
+ sub SRND, 1
+ jne loop1
+
+ mov SRND, 2
+loop2:
+ paddd X0, [TBL + 0*16]
+ movdqa [rsp + _XFER], X0
+ DO_ROUND 0
+ DO_ROUND 1
+ DO_ROUND 2
+ DO_ROUND 3
+ paddd X1, [TBL + 1*16]
+ movdqa [rsp + _XFER], X1
+ add TBL, 2*16
+ DO_ROUND 0
+ DO_ROUND 1
+ DO_ROUND 2
+ DO_ROUND 3
+
+ movdqa X0, X2
+ movdqa X1, X3
+
+ sub SRND, 1
+ jne loop2
+
+ addm [4*0 + CTX],a
+ addm [4*1 + CTX],b
+ addm [4*2 + CTX],c
+ addm [4*3 + CTX],d
+ addm [4*4 + CTX],e
+ addm [4*5 + CTX],f
+ addm [4*6 + CTX],g
+ addm [4*7 + CTX],h
+
+ mov INP, [rsp + _INP]
+ add INP, 64
+ cmp INP, [rsp + _INP_END]
+ jne loop0
+
+done_hash:
+%ifndef LINUX
+ movdqa xmm6,[rsp + _XMM_SAVE + 0*16]
+ movdqa xmm7,[rsp + _XMM_SAVE + 1*16]
+ movdqa xmm8,[rsp + _XMM_SAVE + 2*16]
+ movdqa xmm9,[rsp + _XMM_SAVE + 3*16]
+ movdqa xmm10,[rsp + _XMM_SAVE + 4*16]
+ movdqa xmm11,[rsp + _XMM_SAVE + 5*16]
+ movdqa xmm12,[rsp + _XMM_SAVE + 6*16]
+%endif
+
+ add rsp, STACK_SIZE
+
+ pop r15
+ pop r14
+ pop r13
+ pop rbp
+%ifndef LINUX
+ pop rdi
+ pop rsi
+%endif
+ pop rbx
+
+ ret
+
+
+section .data
+align 64
+K256:
+ dd 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
+ dd 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
+ dd 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
+ dd 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
+ dd 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
+ dd 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
+ dd 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
+ dd 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
+ dd 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
+ dd 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
+ dd 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
+ dd 0xd192e819,0xd6990624,0xf40e3585,0x106aa070
+ dd 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
+ dd 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
+ dd 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
+ dd 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
+
+PSHUFFLE_BYTE_FLIP_MASK: ddq 0x0c0d0e0f08090a0b0405060700010203
+
+; shuffle xBxA -> 00BA
+_SHUF_00BA: ddq 0xFFFFFFFFFFFFFFFF0b0a090803020100
+
+; shuffle xDxC -> DC00
+_SHUF_DC00: ddq 0x0b0a090803020100FFFFFFFFFFFFFFFF
+*/
+
+#endif
diff --git a/src/cuckoocache.h b/src/cuckoocache.h
index efd6a820b5..947e1a7185 100644
--- a/src/cuckoocache.h
+++ b/src/cuckoocache.h
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef _BITCOIN_CUCKOOCACHE_H_
-#define _BITCOIN_CUCKOOCACHE_H_
+#ifndef BITCOIN_CUCKOOCACHE_H
+#define BITCOIN_CUCKOOCACHE_H
#include <array>
#include <algorithm>
@@ -58,7 +58,7 @@ public:
* @post All calls to bit_is_set (without subsequent bit_unset) will return
* true.
*/
- bit_packed_atomic_flags(uint32_t size)
+ explicit bit_packed_atomic_flags(uint32_t size)
{
// pad out the size if needed
size = (size + 7) / 8;
@@ -154,7 +154,7 @@ public:
* @tparam Element should be a movable and copyable type
* @tparam Hash should be a function/callable which takes a template parameter
* hash_select and an Element and extracts a hash from it. Should return
- * high-entropy hashes for `Hash h; h<0>(e) ... h<7>(e)`.
+ * high-entropy uint32_t hashes for `Hash h; h<0>(e) ... h<7>(e)`.
*/
template <typename Element, typename Hash>
class cache
@@ -176,7 +176,7 @@ private:
*/
mutable std::vector<bool> epoch_flags;
- /** epoch_heuristic_counter is used to determine when a epoch might be aged
+ /** epoch_heuristic_counter is used to determine when an epoch might be aged
* & an expensive scan should be done. epoch_heuristic_counter is
* decremented on insert and reset to the new number of inserts which would
* cause the epoch to reach epoch_size when it reaches zero.
@@ -184,7 +184,7 @@ private:
uint32_t epoch_heuristic_counter;
/** epoch_size is set to be the number of elements supposed to be in a
- * epoch. When the number of non-erased elements in a epoch
+ * epoch. When the number of non-erased elements in an epoch
* exceeds epoch_size, a new epoch should be started and all
* current entries demoted. epoch_size is set to be 45% of size because
* we want to keep load around 90%, and we support 3 epochs at once --
@@ -193,12 +193,6 @@ private:
*/
uint32_t epoch_size;
- /** hash_mask should be set to appropriately mask out a hash such that every
- * masked hash is [0,size), eg, if floor(log2(size)) == 20, then hash_mask
- * should be (1<<20)-1
- */
- uint32_t hash_mask;
-
/** depth_limit determines how many elements insert should try to replace.
* Should be set to log2(n)*/
uint8_t depth_limit;
@@ -212,19 +206,50 @@ private:
/** compute_hashes is convenience for not having to write out this
* expression everywhere we use the hash values of an Element.
*
+ * We need to map the 32-bit input hash onto a hash bucket in a range [0, size) in a
+ * manner which preserves as much of the hash's uniformity as possible. Ideally
+ * this would be done by bitmasking but the size is usually not a power of two.
+ *
+ * The naive approach would be to use a mod -- which isn't perfectly uniform but so
+ * long as the hash is much larger than size it is not that bad. Unfortunately,
+ * mod/division is fairly slow on ordinary microprocessors (e.g. 90-ish cycles on
+ * haswell, ARM doesn't even have an instruction for it.); when the divisor is a
+ * constant the compiler will do clever tricks to turn it into a multiply+add+shift,
+ * but size is a run-time value so the compiler can't do that here.
+ *
+ * One option would be to implement the same trick the compiler uses and compute the
+ * constants for exact division based on the size, as described in "{N}-bit Unsigned
+ * Division via {N}-bit Multiply-Add" by Arch D. Robison in 2005. But that code is
+ * somewhat complicated and the result is still slower than other options:
+ *
+ * Instead we treat the 32-bit random number as a Q32 fixed-point number in the range
+ * [0,1) and simply multiply it by the size. Then we just shift the result down by
+ * 32-bits to get our bucket number. The results has non-uniformity the same as a
+ * mod, but it is much faster to compute. More about this technique can be found at
+ * http://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
+ *
+ * The resulting non-uniformity is also more equally distributed which would be
+ * advantageous for something like linear probing, though it shouldn't matter
+ * one way or the other for a cuckoo table.
+ *
+ * The primary disadvantage of this approach is increased intermediate precision is
+ * required but for a 32-bit random number we only need the high 32 bits of a
+ * 32*32->64 multiply, which means the operation is reasonably fast even on a
+ * typical 32-bit processor.
+ *
* @param e the element whose hashes will be returned
* @returns std::array<uint32_t, 8> of deterministic hashes derived from e
*/
inline std::array<uint32_t, 8> compute_hashes(const Element& e) const
{
- return {{hash_function.template operator()<0>(e) & hash_mask,
- hash_function.template operator()<1>(e) & hash_mask,
- hash_function.template operator()<2>(e) & hash_mask,
- hash_function.template operator()<3>(e) & hash_mask,
- hash_function.template operator()<4>(e) & hash_mask,
- hash_function.template operator()<5>(e) & hash_mask,
- hash_function.template operator()<6>(e) & hash_mask,
- hash_function.template operator()<7>(e) & hash_mask}};
+ return {{(uint32_t)((hash_function.template operator()<0>(e) * (uint64_t)size) >> 32),
+ (uint32_t)((hash_function.template operator()<1>(e) * (uint64_t)size) >> 32),
+ (uint32_t)((hash_function.template operator()<2>(e) * (uint64_t)size) >> 32),
+ (uint32_t)((hash_function.template operator()<3>(e) * (uint64_t)size) >> 32),
+ (uint32_t)((hash_function.template operator()<4>(e) * (uint64_t)size) >> 32),
+ (uint32_t)((hash_function.template operator()<5>(e) * (uint64_t)size) >> 32),
+ (uint32_t)((hash_function.template operator()<6>(e) * (uint64_t)size) >> 32),
+ (uint32_t)((hash_function.template operator()<7>(e) * (uint64_t)size) >> 32)}};
}
/* end
@@ -257,7 +282,7 @@ private:
*
* First, epoch_check decrements and checks the cheap heuristic, and then does
* a more expensive scan if the cheap heuristic runs out. If the expensive
- * scan suceeds, the epochs are aged and old elements are allow_erased. The
+ * scan succeeds, the epochs are aged and old elements are allow_erased. The
* cheap heuristic is reset to retrigger after the worst case growth of the
* current epoch's elements would exceed the epoch_size.
*/
@@ -305,7 +330,7 @@ public:
}
/** setup initializes the container to store no more than new_size
- * elements. setup rounds down to a power of two size.
+ * elements.
*
* setup should only be called once.
*
@@ -316,8 +341,7 @@ public:
{
// depth_limit must be at least one otherwise errors can occur.
depth_limit = static_cast<uint8_t>(std::log2(static_cast<float>(std::max((uint32_t)2, new_size))));
- size = 1 << depth_limit;
- hash_mask = size-1;
+ size = std::max<uint32_t>(2, new_size);
table.resize(size);
collection_flags.setup(size);
epoch_flags.resize(size);
@@ -395,7 +419,7 @@ public:
* 1) On first iteration, last_loc == invalid(), find returns last, so
* last_loc defaults to locs[0].
* 2) On further iterations, where last_loc == locs[k], last_loc will
- * go to locs[k+1 % 8], i.e., next of the 8 indicies wrapping around
+ * go to locs[k+1 % 8], i.e., next of the 8 indices wrapping around
* to 0 if needed.
*
* This prevents moving the element we just put in.
@@ -454,4 +478,4 @@ public:
};
} // namespace CuckooCache
-#endif
+#endif // BITCOIN_CUCKOOCACHE_H
diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp
index 94ebedeb72..dfc90f3ab9 100644
--- a/src/dbwrapper.cpp
+++ b/src/dbwrapper.cpp
@@ -4,16 +4,74 @@
#include "dbwrapper.h"
+#include "fs.h"
#include "util.h"
#include "random.h"
-#include <boost/filesystem.hpp>
-
#include <leveldb/cache.h>
#include <leveldb/env.h>
#include <leveldb/filter_policy.h>
#include <memenv.h>
#include <stdint.h>
+#include <algorithm>
+
+class CBitcoinLevelDBLogger : public leveldb::Logger {
+public:
+ // This code is adapted from posix_logger.h, which is why it is using vsprintf.
+ // Please do not do this in normal code
+ void Logv(const char * format, va_list ap) override {
+ if (!LogAcceptCategory(BCLog::LEVELDB)) {
+ return;
+ }
+ char buffer[500];
+ for (int iter = 0; iter < 2; iter++) {
+ char* base;
+ int bufsize;
+ if (iter == 0) {
+ bufsize = sizeof(buffer);
+ base = buffer;
+ }
+ else {
+ bufsize = 30000;
+ base = new char[bufsize];
+ }
+ char* p = base;
+ char* limit = base + bufsize;
+
+ // Print the message
+ if (p < limit) {
+ va_list backup_ap;
+ va_copy(backup_ap, ap);
+ // Do not use vsnprintf elsewhere in bitcoin source code, see above.
+ p += vsnprintf(p, limit - p, format, backup_ap);
+ va_end(backup_ap);
+ }
+
+ // Truncate to available space if necessary
+ if (p >= limit) {
+ if (iter == 0) {
+ continue; // Try again with larger buffer
+ }
+ else {
+ p = limit - 1;
+ }
+ }
+
+ // Add newline if necessary
+ if (p == base || p[-1] != '\n') {
+ *p++ = '\n';
+ }
+
+ assert(p <= limit);
+ base[std::min(bufsize - 1, (int)(p - base))] = '\0';
+ LogPrintStr(base);
+ if (base != buffer) {
+ delete[] base;
+ }
+ break;
+ }
+ }
+};
static leveldb::Options GetOptions(size_t nCacheSize)
{
@@ -23,6 +81,7 @@ static leveldb::Options GetOptions(size_t nCacheSize)
options.filter_policy = leveldb::NewBloomFilterPolicy(10);
options.compression = leveldb::kNoCompression;
options.max_open_files = 64;
+ options.info_log = new CBitcoinLevelDBLogger();
if (leveldb::kMajorVersion > 1 || (leveldb::kMajorVersion == 1 && leveldb::kMinorVersion >= 16)) {
// LevelDB versions before 1.16 consider short writes to be corruption. Only trigger error
// on corruption in later versions.
@@ -31,9 +90,9 @@ static leveldb::Options GetOptions(size_t nCacheSize)
return options;
}
-CDBWrapper::CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate)
+CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate)
{
- penv = NULL;
+ penv = nullptr;
readoptions.verify_checksums = true;
iteroptions.verify_checksums = true;
iteroptions.fill_cache = false;
@@ -49,13 +108,19 @@ CDBWrapper::CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, b
leveldb::Status result = leveldb::DestroyDB(path.string(), options);
dbwrapper_private::HandleError(result);
}
- TryCreateDirectory(path);
+ TryCreateDirectories(path);
LogPrintf("Opening LevelDB in %s\n", path.string());
}
leveldb::Status status = leveldb::DB::Open(options, path.string(), &pdb);
dbwrapper_private::HandleError(status);
LogPrintf("Opened LevelDB successfully\n");
+ if (gArgs.GetBoolArg("-forcecompactdb", false)) {
+ LogPrintf("Starting database compaction of %s\n", path.string());
+ pdb->CompactRange(nullptr, nullptr);
+ LogPrintf("Finished database compaction of %s\n", path.string());
+ }
+
// The base-case obfuscation key, which is a noop.
obfuscate_key = std::vector<unsigned char>(OBFUSCATE_KEY_NUM_BYTES, '\000');
@@ -79,13 +144,15 @@ CDBWrapper::CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, b
CDBWrapper::~CDBWrapper()
{
delete pdb;
- pdb = NULL;
+ pdb = nullptr;
delete options.filter_policy;
- options.filter_policy = NULL;
+ options.filter_policy = nullptr;
+ delete options.info_log;
+ options.info_log = nullptr;
delete options.block_cache;
- options.block_cache = NULL;
+ options.block_cache = nullptr;
delete penv;
- options.env = NULL;
+ options.env = nullptr;
}
bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync)
@@ -123,7 +190,7 @@ bool CDBWrapper::IsEmpty()
}
CDBIterator::~CDBIterator() { delete piter; }
-bool CDBIterator::Valid() { return piter->Valid(); }
+bool CDBIterator::Valid() const { return piter->Valid(); }
void CDBIterator::SeekToFirst() { piter->SeekToFirst(); }
void CDBIterator::Next() { piter->Next(); }
@@ -148,4 +215,4 @@ const std::vector<unsigned char>& GetObfuscateKey(const CDBWrapper &w)
return w.obfuscate_key;
}
-};
+} // namespace dbwrapper_private
diff --git a/src/dbwrapper.h b/src/dbwrapper.h
index dd59cc00ff..e19fde51c1 100644
--- a/src/dbwrapper.h
+++ b/src/dbwrapper.h
@@ -6,14 +6,13 @@
#define BITCOIN_DBWRAPPER_H
#include "clientversion.h"
+#include "fs.h"
#include "serialize.h"
#include "streams.h"
#include "util.h"
#include "utilstrencodings.h"
#include "version.h"
-#include <boost/filesystem/path.hpp>
-
#include <leveldb/db.h>
#include <leveldb/write_batch.h>
@@ -23,7 +22,7 @@ static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;
class dbwrapper_error : public std::runtime_error
{
public:
- dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {}
+ explicit dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {}
};
class CDBWrapper;
@@ -56,11 +55,19 @@ private:
CDataStream ssKey;
CDataStream ssValue;
+ size_t size_estimate;
+
public:
/**
* @param[in] _parent CDBWrapper that this batch is to be submitted to
*/
- CDBBatch(const CDBWrapper &_parent) : parent(_parent), ssKey(SER_DISK, CLIENT_VERSION), ssValue(SER_DISK, CLIENT_VERSION) { };
+ explicit CDBBatch(const CDBWrapper &_parent) : parent(_parent), ssKey(SER_DISK, CLIENT_VERSION), ssValue(SER_DISK, CLIENT_VERSION), size_estimate(0) { };
+
+ void Clear()
+ {
+ batch.Clear();
+ size_estimate = 0;
+ }
template <typename K, typename V>
void Write(const K& key, const V& value)
@@ -75,6 +82,14 @@ public:
leveldb::Slice slValue(ssValue.data(), ssValue.size());
batch.Put(slKey, slValue);
+ // LevelDB serializes writes as:
+ // - byte: header
+ // - varint: key length (1 byte up to 127B, 2 bytes up to 16383B, ...)
+ // - byte[]: key
+ // - varint: value length
+ // - byte[]: value
+ // The formula below assumes the key and value are both less than 16k.
+ size_estimate += 3 + (slKey.size() > 127) + slKey.size() + (slValue.size() > 127) + slValue.size();
ssKey.clear();
ssValue.clear();
}
@@ -87,8 +102,16 @@ public:
leveldb::Slice slKey(ssKey.data(), ssKey.size());
batch.Delete(slKey);
+ // LevelDB serializes erases as:
+ // - byte: header
+ // - varint: key length
+ // - byte[]: key
+ // The formula below assumes the key is less than 16kB.
+ size_estimate += 2 + (slKey.size() > 127) + slKey.size();
ssKey.clear();
}
+
+ size_t SizeEstimate() const { return size_estimate; }
};
class CDBIterator
@@ -107,7 +130,7 @@ public:
parent(_parent), piter(_piter) { };
~CDBIterator();
- bool Valid();
+ bool Valid() const;
void SeekToFirst();
@@ -132,10 +155,6 @@ public:
return true;
}
- unsigned int GetKeySize() {
- return piter->key().size();
- }
-
template<typename V> bool GetValue(V& value) {
leveldb::Slice slValue = piter->value();
try {
@@ -158,7 +177,7 @@ class CDBWrapper
{
friend const std::vector<unsigned char>& dbwrapper_private::GetObfuscateKey(const CDBWrapper &w);
private:
- //! custom environment this database is using (may be NULL in case of default environment)
+ //! custom environment this database is using (may be nullptr in case of default environment)
leveldb::Env* penv;
//! database options used
@@ -199,7 +218,7 @@ public:
* @param[in] obfuscate If true, store data obfuscated via simple XOR. If false, XOR
* with a zero'd byte array.
*/
- CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool obfuscate = false);
+ CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool obfuscate = false);
~CDBWrapper();
template <typename K, typename V>
@@ -286,7 +305,39 @@ public:
* Return true if the database managed by this class contains no entries.
*/
bool IsEmpty();
+
+ template<typename K>
+ size_t EstimateSize(const K& key_begin, const K& key_end) const
+ {
+ CDataStream ssKey1(SER_DISK, CLIENT_VERSION), ssKey2(SER_DISK, CLIENT_VERSION);
+ ssKey1.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
+ ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
+ ssKey1 << key_begin;
+ ssKey2 << key_end;
+ leveldb::Slice slKey1(ssKey1.data(), ssKey1.size());
+ leveldb::Slice slKey2(ssKey2.data(), ssKey2.size());
+ uint64_t size = 0;
+ leveldb::Range range(slKey1, slKey2);
+ pdb->GetApproximateSizes(&range, 1, &size);
+ return size;
+ }
+
+ /**
+ * Compact a certain range of keys in the database.
+ */
+ template<typename K>
+ void CompactRange(const K& key_begin, const K& key_end) const
+ {
+ CDataStream ssKey1(SER_DISK, CLIENT_VERSION), ssKey2(SER_DISK, CLIENT_VERSION);
+ ssKey1.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
+ ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
+ ssKey1 << key_begin;
+ ssKey2 << key_end;
+ leveldb::Slice slKey1(ssKey1.data(), ssKey1.size());
+ leveldb::Slice slKey2(ssKey2.data(), ssKey2.size());
+ pdb->CompactRange(&slKey1, &slKey2);
+ }
+
};
#endif // BITCOIN_DBWRAPPER_H
-
diff --git a/src/fs.cpp b/src/fs.cpp
new file mode 100644
index 0000000000..a5e12f1cfc
--- /dev/null
+++ b/src/fs.cpp
@@ -0,0 +1,15 @@
+#include "fs.h"
+
+namespace fsbridge {
+
+FILE *fopen(const fs::path& p, const char *mode)
+{
+ return ::fopen(p.string().c_str(), mode);
+}
+
+FILE *freopen(const fs::path& p, const char *mode, FILE *stream)
+{
+ return ::freopen(p.string().c_str(), mode, stream);
+}
+
+} // fsbridge
diff --git a/src/fs.h b/src/fs.h
new file mode 100644
index 0000000000..abb4be254b
--- /dev/null
+++ b/src/fs.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2017 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_FS_H
+#define BITCOIN_FS_H
+
+#include <stdio.h>
+#include <string>
+
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/filesystem/detail/utf8_codecvt_facet.hpp>
+
+/** Filesystem operations and types */
+namespace fs = boost::filesystem;
+
+/** Bridge operations to C stdio */
+namespace fsbridge {
+ FILE *fopen(const fs::path& p, const char *mode);
+ FILE *freopen(const fs::path& p, const char *mode, FILE *stream);
+};
+
+#endif // BITCOIN_FS_H
diff --git a/src/hash.cpp b/src/hash.cpp
index a399ca9252..5a15600be5 100644
--- a/src/hash.cpp
+++ b/src/hash.cpp
@@ -17,36 +17,34 @@ unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char
{
// The following is MurmurHash3 (x86_32), see http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp
uint32_t h1 = nHashSeed;
- if (vDataToHash.size() > 0)
- {
- const uint32_t c1 = 0xcc9e2d51;
- const uint32_t c2 = 0x1b873593;
+ const uint32_t c1 = 0xcc9e2d51;
+ const uint32_t c2 = 0x1b873593;
- const int nblocks = vDataToHash.size() / 4;
+ const int nblocks = vDataToHash.size() / 4;
- //----------
- // body
- const uint8_t* blocks = &vDataToHash[0] + nblocks * 4;
+ //----------
+ // body
+ const uint8_t* blocks = vDataToHash.data();
- for (int i = -nblocks; i; i++) {
- uint32_t k1 = ReadLE32(blocks + i*4);
+ for (int i = 0; i < nblocks; ++i) {
+ uint32_t k1 = ReadLE32(blocks + i*4);
- k1 *= c1;
- k1 = ROTL32(k1, 15);
- k1 *= c2;
+ k1 *= c1;
+ k1 = ROTL32(k1, 15);
+ k1 *= c2;
- h1 ^= k1;
- h1 = ROTL32(h1, 13);
- h1 = h1 * 5 + 0xe6546b64;
- }
+ h1 ^= k1;
+ h1 = ROTL32(h1, 13);
+ h1 = h1 * 5 + 0xe6546b64;
+ }
- //----------
- // tail
- const uint8_t* tail = (const uint8_t*)(&vDataToHash[0] + nblocks * 4);
+ //----------
+ // tail
+ const uint8_t* tail = vDataToHash.data() + nblocks * 4;
- uint32_t k1 = 0;
+ uint32_t k1 = 0;
- switch (vDataToHash.size() & 3) {
+ switch (vDataToHash.size() & 3) {
case 3:
k1 ^= tail[2] << 16;
case 2:
@@ -57,7 +55,6 @@ unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char
k1 = ROTL32(k1, 15);
k1 *= c2;
h1 ^= k1;
- };
}
//----------
@@ -208,3 +205,44 @@ uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val)
SIPROUND;
return v0 ^ v1 ^ v2 ^ v3;
}
+
+uint64_t SipHashUint256Extra(uint64_t k0, uint64_t k1, const uint256& val, uint32_t extra)
+{
+ /* Specialized implementation for efficiency */
+ uint64_t d = val.GetUint64(0);
+
+ uint64_t v0 = 0x736f6d6570736575ULL ^ k0;
+ uint64_t v1 = 0x646f72616e646f6dULL ^ k1;
+ uint64_t v2 = 0x6c7967656e657261ULL ^ k0;
+ uint64_t v3 = 0x7465646279746573ULL ^ k1 ^ d;
+
+ SIPROUND;
+ SIPROUND;
+ v0 ^= d;
+ d = val.GetUint64(1);
+ v3 ^= d;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= d;
+ d = val.GetUint64(2);
+ v3 ^= d;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= d;
+ d = val.GetUint64(3);
+ v3 ^= d;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= d;
+ d = (((uint64_t)36) << 56) | extra;
+ v3 ^= d;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= d;
+ v2 ^= 0xFF;
+ SIPROUND;
+ SIPROUND;
+ SIPROUND;
+ SIPROUND;
+ return v0 ^ v1 ^ v2 ^ v3;
+}
diff --git a/src/hash.h b/src/hash.h
index 3b86fcc033..474b13d65b 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -25,9 +25,9 @@ public:
static const size_t OUTPUT_SIZE = CSHA256::OUTPUT_SIZE;
void Finalize(unsigned char hash[OUTPUT_SIZE]) {
- unsigned char buf[sha.OUTPUT_SIZE];
+ unsigned char buf[CSHA256::OUTPUT_SIZE];
sha.Finalize(buf);
- sha.Reset().Write(buf, sha.OUTPUT_SIZE).Finalize(hash);
+ sha.Reset().Write(buf, CSHA256::OUTPUT_SIZE).Finalize(hash);
}
CHash256& Write(const unsigned char *data, size_t len) {
@@ -49,9 +49,9 @@ public:
static const size_t OUTPUT_SIZE = CRIPEMD160::OUTPUT_SIZE;
void Finalize(unsigned char hash[OUTPUT_SIZE]) {
- unsigned char buf[sha.OUTPUT_SIZE];
+ unsigned char buf[CSHA256::OUTPUT_SIZE];
sha.Finalize(buf);
- CRIPEMD160().Write(buf, sha.OUTPUT_SIZE).Finalize(hash);
+ CRIPEMD160().Write(buf, CSHA256::OUTPUT_SIZE).Finalize(hash);
}
CHash160& Write(const unsigned char *data, size_t len) {
@@ -88,20 +88,6 @@ inline uint256 Hash(const T1 p1begin, const T1 p1end,
return result;
}
-/** Compute the 256-bit hash of the concatenation of three objects. */
-template<typename T1, typename T2, typename T3>
-inline uint256 Hash(const T1 p1begin, const T1 p1end,
- const T2 p2begin, const T2 p2end,
- const T3 p3begin, const T3 p3end) {
- static const unsigned char pblank[1] = {};
- uint256 result;
- CHash256().Write(p1begin == p1end ? pblank : (const unsigned char*)&p1begin[0], (p1end - p1begin) * sizeof(p1begin[0]))
- .Write(p2begin == p2end ? pblank : (const unsigned char*)&p2begin[0], (p2end - p2begin) * sizeof(p2begin[0]))
- .Write(p3begin == p3end ? pblank : (const unsigned char*)&p3begin[0], (p3end - p3begin) * sizeof(p3begin[0]))
- .Finalize((unsigned char*)&result);
- return result;
-}
-
/** Compute the 160-bit hash an object. */
template<typename T1>
inline uint160 Hash160(const T1 pbegin, const T1 pend)
@@ -160,6 +146,41 @@ public:
}
};
+/** Reads data from an underlying stream, while hashing the read data. */
+template<typename Source>
+class CHashVerifier : public CHashWriter
+{
+private:
+ Source* source;
+
+public:
+ explicit CHashVerifier(Source* source_) : CHashWriter(source_->GetType(), source_->GetVersion()), source(source_) {}
+
+ void read(char* pch, size_t nSize)
+ {
+ source->read(pch, nSize);
+ this->write(pch, nSize);
+ }
+
+ void ignore(size_t nSize)
+ {
+ char data[1024];
+ while (nSize > 0) {
+ size_t now = std::min<size_t>(nSize, 1024);
+ read(data, now);
+ nSize -= now;
+ }
+ }
+
+ template<typename T>
+ CHashVerifier<Source>& operator>>(T& obj)
+ {
+ // Unserialize from this stream
+ ::Unserialize(*this, obj);
+ return (*this);
+ }
+};
+
/** Compute the 256-bit hash of an object's serialization. */
template<typename T>
uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
@@ -206,5 +227,6 @@ public:
* .Finalize()
*/
uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val);
+uint64_t SipHashUint256Extra(uint64_t k0, uint64_t k1, const uint256& val, uint32_t extra);
#endif // BITCOIN_HASH_H
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index 742ff2b8fb..91f96ef207 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -16,21 +16,19 @@
#include "ui_interface.h"
#include "crypto/hmac_sha256.h"
#include <stdio.h>
-#include "utilstrencodings.h"
#include <boost/algorithm/string.hpp> // boost::trim
-#include <boost/foreach.hpp> //BOOST_FOREACH
/** WWW-Authenticate to present with 401 Unauthorized response */
static const char* WWW_AUTH_HEADER_DATA = "Basic realm=\"jsonrpc\"";
/** Simple one-shot callback timer to be used by the RPC mechanism to e.g.
- * re-lock the wellet.
+ * re-lock the wallet.
*/
class HTTPRPCTimer : public RPCTimerBase
{
public:
- HTTPRPCTimer(struct event_base* eventBase, boost::function<void(void)>& func, int64_t millis) :
+ HTTPRPCTimer(struct event_base* eventBase, std::function<void(void)>& func, int64_t millis) :
ev(eventBase, false, func)
{
struct timeval tv;
@@ -45,14 +43,14 @@ private:
class HTTPRPCTimerInterface : public RPCTimerInterface
{
public:
- HTTPRPCTimerInterface(struct event_base* _base) : base(_base)
+ explicit HTTPRPCTimerInterface(struct event_base* _base) : base(_base)
{
}
- const char* Name()
+ const char* Name() override
{
return "HTTP";
}
- RPCTimerBase* NewTimer(boost::function<void(void)>& func, int64_t millis)
+ RPCTimerBase* NewTimer(std::function<void(void)>& func, int64_t millis) override
{
return new HTTPRPCTimer(base, func, millis);
}
@@ -64,7 +62,7 @@ private:
/* Pre-base64-encoded authentication token */
static std::string strRPCUserColonPass;
/* Stored RPC timer interface (for unregistration) */
-static HTTPRPCTimerInterface* httpRPCTimerInterface = 0;
+static HTTPRPCTimerInterface* httpRPCTimerInterface = nullptr;
static void JSONErrorReply(HTTPRequest* req, const UniValue& objError, const UniValue& id)
{
@@ -93,35 +91,32 @@ static bool multiUserAuthorized(std::string strUserPass)
std::string strUser = strUserPass.substr(0, strUserPass.find(":"));
std::string strPass = strUserPass.substr(strUserPass.find(":") + 1);
- if (mapMultiArgs.count("-rpcauth") > 0) {
+ for (const std::string& strRPCAuth : gArgs.GetArgs("-rpcauth")) {
//Search for multi-user login/pass "rpcauth" from config
- BOOST_FOREACH(std::string strRPCAuth, mapMultiArgs.at("-rpcauth"))
- {
- std::vector<std::string> vFields;
- boost::split(vFields, strRPCAuth, boost::is_any_of(":$"));
- if (vFields.size() != 3) {
- //Incorrect formatting in config file
- continue;
- }
-
- std::string strName = vFields[0];
- if (!TimingResistantEqual(strName, strUser)) {
- continue;
- }
-
- std::string strSalt = vFields[1];
- std::string strHash = vFields[2];
-
- unsigned int KEY_SIZE = 32;
- unsigned char *out = new unsigned char[KEY_SIZE];
-
- CHMAC_SHA256(reinterpret_cast<const unsigned char*>(strSalt.c_str()), strSalt.size()).Write(reinterpret_cast<const unsigned char*>(strPass.c_str()), strPass.size()).Finalize(out);
- std::vector<unsigned char> hexvec(out, out+KEY_SIZE);
- std::string strHashFromPass = HexStr(hexvec);
-
- if (TimingResistantEqual(strHashFromPass, strHash)) {
- return true;
- }
+ std::vector<std::string> vFields;
+ boost::split(vFields, strRPCAuth, boost::is_any_of(":$"));
+ if (vFields.size() != 3) {
+ //Incorrect formatting in config file
+ continue;
+ }
+
+ std::string strName = vFields[0];
+ if (!TimingResistantEqual(strName, strUser)) {
+ continue;
+ }
+
+ std::string strSalt = vFields[1];
+ std::string strHash = vFields[2];
+
+ static const unsigned int KEY_SIZE = 32;
+ unsigned char out[KEY_SIZE];
+
+ CHMAC_SHA256(reinterpret_cast<const unsigned char*>(strSalt.c_str()), strSalt.size()).Write(reinterpret_cast<const unsigned char*>(strPass.c_str()), strPass.size()).Finalize(out);
+ std::vector<unsigned char> hexvec(out, out+KEY_SIZE);
+ std::string strHashFromPass = HexStr(hexvec);
+
+ if (TimingResistantEqual(strHashFromPass, strHash)) {
+ return true;
}
}
return false;
@@ -215,7 +210,7 @@ static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &)
static bool InitRPCAuthentication()
{
- if (GetArg("-rpcpassword", "") == "")
+ if (gArgs.GetArg("-rpcpassword", "") == "")
{
LogPrintf("No rpcpassword set - using random cookie authentication\n");
if (!GenerateAuthCookie(&strRPCUserColonPass)) {
@@ -226,19 +221,22 @@ static bool InitRPCAuthentication()
}
} else {
LogPrintf("Config options rpcuser and rpcpassword will soon be deprecated. Locally-run instances may remove rpcuser to use cookie-based auth, or may be replaced with rpcauth. Please see share/rpcuser for rpcauth auth generation.\n");
- strRPCUserColonPass = GetArg("-rpcuser", "") + ":" + GetArg("-rpcpassword", "");
+ strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" + gArgs.GetArg("-rpcpassword", "");
}
return true;
}
bool StartHTTPRPC()
{
- LogPrint("rpc", "Starting HTTP RPC server\n");
+ LogPrint(BCLog::RPC, "Starting HTTP RPC server\n");
if (!InitRPCAuthentication())
return false;
RegisterHTTPHandler("/", true, HTTPReq_JSONRPC);
-
+#ifdef ENABLE_WALLET
+ // ifdef can be removed once we switch to better endpoint support and API versioning
+ RegisterHTTPHandler("/wallet/", false, HTTPReq_JSONRPC);
+#endif
assert(EventBase());
httpRPCTimerInterface = new HTTPRPCTimerInterface(EventBase());
RPCSetTimerInterface(httpRPCTimerInterface);
@@ -247,16 +245,16 @@ bool StartHTTPRPC()
void InterruptHTTPRPC()
{
- LogPrint("rpc", "Interrupting HTTP RPC server\n");
+ LogPrint(BCLog::RPC, "Interrupting HTTP RPC server\n");
}
void StopHTTPRPC()
{
- LogPrint("rpc", "Stopping HTTP RPC server\n");
+ LogPrint(BCLog::RPC, "Stopping HTTP RPC server\n");
UnregisterHTTPHandler("/", true);
if (httpRPCTimerInterface) {
RPCUnsetTimerInterface(httpRPCTimerInterface);
delete httpRPCTimerInterface;
- httpRPCTimerInterface = 0;
+ httpRPCTimerInterface = nullptr;
}
}
diff --git a/src/httprpc.h b/src/httprpc.h
index d354457188..a89a8f0fbf 100644
--- a/src/httprpc.h
+++ b/src/httprpc.h
@@ -8,8 +8,6 @@
#include <string>
#include <map>
-class HTTPRequest;
-
/** Start HTTP RPC subsystem.
* Precondition; HTTP and RPC has been started.
*/
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index 1692b43f28..5923871691 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -7,6 +7,7 @@
#include "chainparamsbase.h"
#include "compat.h"
#include "util.h"
+#include "utilstrencodings.h"
#include "netbase.h"
#include "rpc/protocol.h" // For HTTP status codes
#include "sync.h"
@@ -21,13 +22,13 @@
#include <signal.h>
#include <future>
-#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>
+#include "support/events.h"
+
#ifdef EVENT__HAVE_NETINET_IN_H
#include <netinet/in.h>
#ifdef _XOPEN_SOURCE_EXTENDED
@@ -39,14 +40,14 @@
static const size_t MAX_HEADERS_SIZE = 8192;
/** HTTP request work item */
-class HTTPWorkItem : public HTTPClosure
+class HTTPWorkItem final : public HTTPClosure
{
public:
HTTPWorkItem(std::unique_ptr<HTTPRequest> _req, const std::string &_path, const HTTPRequestHandler& _func):
req(std::move(_req)), path(_path), func(_func)
{
}
- void operator()()
+ void operator()() override
{
func(req.get(), path);
}
@@ -78,7 +79,7 @@ private:
{
public:
WorkQueue &wq;
- ThreadCounter(WorkQueue &w): wq(w)
+ explicit ThreadCounter(WorkQueue &w): wq(w)
{
std::lock_guard<std::mutex> lock(wq.cs);
wq.numThreads += 1;
@@ -92,7 +93,7 @@ private:
};
public:
- WorkQueue(size_t _maxDepth) : running(true),
+ explicit WorkQueue(size_t _maxDepth) : running(true),
maxDepth(_maxDepth),
numThreads(0)
{
@@ -118,7 +119,7 @@ public:
void Run()
{
ThreadCounter count(*this);
- while (running) {
+ while (true) {
std::unique_ptr<WorkItem> i;
{
std::unique_lock<std::mutex> lock(cs);
@@ -146,13 +147,6 @@ public:
while (numThreads > 0)
cond.wait(lock);
}
-
- /** Return current depth of queue */
- size_t Depth()
- {
- std::unique_lock<std::mutex> lock(cs);
- return queue.size();
- }
};
struct HTTPPathHandler
@@ -170,13 +164,13 @@ struct HTTPPathHandler
/** HTTP module state */
//! libevent event loop
-static struct event_base* eventBase = 0;
+static struct event_base* eventBase = nullptr;
//! HTTP server
-struct evhttp* eventHTTP = 0;
+struct evhttp* eventHTTP = nullptr;
//! 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;
+static WorkQueue<HTTPClosure>* workQueue = nullptr;
//! Handlers for (sub)paths
std::vector<HTTPPathHandler> pathHandlers;
//! Bound listening sockets
@@ -203,24 +197,21 @@ static bool InitHTTPAllowList()
LookupHost("::1", localv6, false);
rpc_allow_subnets.push_back(CSubNet(localv4, 8)); // always allow IPv4 local subnet
rpc_allow_subnets.push_back(CSubNet(localv6)); // always allow IPv6 localhost
- if (mapMultiArgs.count("-rpcallowip")) {
- const std::vector<std::string>& vAllow = mapMultiArgs.at("-rpcallowip");
- for (std::string strAllow : vAllow) {
- CSubNet subnet;
- LookupSubNet(strAllow.c_str(), subnet);
- 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);
+ for (const std::string& strAllow : gArgs.GetArgs("-rpcallowip")) {
+ CSubNet subnet;
+ LookupSubNet(strAllow.c_str(), subnet);
+ 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;
for (const CSubNet& subnet : rpc_allow_subnets)
strAllowed += subnet.ToString() + " ";
- LogPrint("http", "Allowing HTTP connections from: %s\n", strAllowed);
+ LogPrint(BCLog::HTTP, "Allowing HTTP connections from: %s\n", strAllowed);
return true;
}
@@ -250,7 +241,7 @@ static void http_request_cb(struct evhttp_request* req, void* arg)
{
std::unique_ptr<HTTPRequest> hreq(new HTTPRequest(req));
- LogPrint("http", "Received a %s request for %s from %s\n",
+ LogPrint(BCLog::HTTP, "Received a %s request for %s from %s\n",
RequestMethodString(hreq->GetRequestMethod()), hreq->GetURI(), hreq->GetPeer().ToString());
// Early address-based allow check
@@ -300,40 +291,39 @@ static void http_request_cb(struct evhttp_request* req, void* arg)
/** Callback to reject HTTP requests after shutdown. */
static void http_reject_request_cb(struct evhttp_request* req, void*)
{
- LogPrint("http", "Rejecting request while shutting down\n");
- evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
+ LogPrint(BCLog::HTTP, "Rejecting request while shutting down\n");
+ evhttp_send_error(req, HTTP_SERVUNAVAIL, nullptr);
}
/** Event dispatcher thread */
static bool ThreadHTTP(struct event_base* base, struct evhttp* http)
{
RenameThread("bitcoin-http");
- LogPrint("http", "Entering http event loop\n");
+ LogPrint(BCLog::HTTP, "Entering http event loop\n");
event_base_dispatch(base);
// Event loop will be interrupted by InterruptHTTPServer()
- LogPrint("http", "Exited http event loop\n");
+ LogPrint(BCLog::HTTP, "Exited http event loop\n");
return event_base_got_break(base) == 0;
}
/** Bind HTTP server to specified addresses */
static bool HTTPBindAddresses(struct evhttp* http)
{
- int defaultPort = GetArg("-rpcport", BaseParams().RPCPort());
+ int defaultPort = gArgs.GetArg("-rpcport", BaseParams().RPCPort());
std::vector<std::pair<std::string, uint16_t> > endpoints;
// Determine what addresses to bind to
- if (!IsArgSet("-rpcallowip")) { // Default to loopback if not allowing external IPs
+ if (!gArgs.IsArgSet("-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 (IsArgSet("-rpcbind")) {
+ if (gArgs.IsArgSet("-rpcbind")) {
LogPrintf("WARNING: option -rpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\n");
}
- } else if (mapMultiArgs.count("-rpcbind")) { // Specific bind address
- const std::vector<std::string>& vbind = mapMultiArgs.at("-rpcbind");
- for (std::vector<std::string>::const_iterator i = vbind.begin(); i != vbind.end(); ++i) {
+ } else if (gArgs.IsArgSet("-rpcbind")) { // Specific bind address
+ for (const std::string& strRPCBind : gArgs.GetArgs("-rpcbind")) {
int port = defaultPort;
std::string host;
- SplitHostPort(*i, port, host);
+ SplitHostPort(strRPCBind, port, host);
endpoints.push_back(std::make_pair(host, port));
}
} else { // No specific bind address specified, bind to any
@@ -343,8 +333,8 @@ static bool HTTPBindAddresses(struct evhttp* http)
// 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);
- evhttp_bound_socket *bind_handle = evhttp_bind_socket_with_handle(http, i->first.empty() ? NULL : i->first.c_str(), i->second);
+ LogPrint(BCLog::HTTP, "Binding RPC on address %s port %i\n", i->first, i->second);
+ evhttp_bound_socket *bind_handle = evhttp_bind_socket_with_handle(http, i->first.empty() ? nullptr : i->first.c_str(), i->second);
if (bind_handle) {
boundSockets.push_back(bind_handle);
} else {
@@ -371,18 +361,15 @@ 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);
+ LogPrint(BCLog::LIBEVENT, "libevent: %s\n", msg);
}
bool InitHTTPServer()
{
- struct evhttp* http = 0;
- struct event_base* base = 0;
-
if (!InitHTTPAllowList())
return false;
- if (GetBoolArg("-rpcssl", false)) {
+ if (gArgs.GetBoolArg("-rpcssl", false)) {
uiInterface.ThreadSafeMessageBox(
"SSL mode for RPC (-rpcssl) is no longer supported.",
"", CClientUIInterface::MSG_ERROR);
@@ -391,63 +378,71 @@ bool InitHTTPServer()
// 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
+ // Update libevent's log handling. Returns false if our version of
+ // libevent doesn't support debug logging, in which case we should
+ // clear the BCLog::LIBEVENT flag.
+ if (!UpdateHTTPServerLogging(logCategories & BCLog::LIBEVENT)) {
+ logCategories &= ~BCLog::LIBEVENT;
+ }
+
#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;
- }
+ raii_event_base base_ctr = obtain_event_base();
/* Create a new evhttp object to handle requests. */
- http = evhttp_new(base); // XXX RAII
+ raii_evhttp http_ctr = obtain_evhttp(base_ctr.get());
+ struct evhttp* http = http_ctr.get();
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_timeout(http, gArgs.GetArg("-rpcservertimeout", DEFAULT_HTTP_SERVER_TIMEOUT));
evhttp_set_max_headers_size(http, MAX_HEADERS_SIZE);
evhttp_set_max_body_size(http, MAX_SIZE);
- evhttp_set_gencb(http, http_request_cb, NULL);
+ evhttp_set_gencb(http, http_request_cb, nullptr);
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);
+ LogPrint(BCLog::HTTP, "Initialized HTTP server\n");
+ int workQueueDepth = std::max((long)gArgs.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;
+ // transfer ownership to eventBase/HTTP via .release()
+ eventBase = base_ctr.release();
+ eventHTTP = http_ctr.release();
return true;
}
+bool UpdateHTTPServerLogging(bool enable) {
+#if LIBEVENT_VERSION_NUMBER >= 0x02010100
+ if (enable) {
+ event_enable_debug_logging(EVENT_DBG_ALL);
+ } else {
+ event_enable_debug_logging(EVENT_DBG_NONE);
+ }
+ return true;
+#else
+ // Can't update libevent logging if version < 02010100
+ return false;
+#endif
+}
+
std::thread threadHTTP;
std::future<bool> threadResult;
bool StartHTTPServer()
{
- LogPrint("http", "Starting HTTP server\n");
- int rpcThreads = std::max((long)GetArg("-rpcthreads", DEFAULT_HTTP_THREADS), 1L);
+ LogPrint(BCLog::HTTP, "Starting HTTP server\n");
+ int rpcThreads = std::max((long)gArgs.GetArg("-rpcthreads", DEFAULT_HTTP_THREADS), 1L);
LogPrintf("HTTP: starting %d worker threads\n", rpcThreads);
std::packaged_task<bool(event_base*, evhttp*)> task(ThreadHTTP);
threadResult = task.get_future();
@@ -462,14 +457,14 @@ bool StartHTTPServer()
void InterruptHTTPServer()
{
- LogPrint("http", "Interrupting HTTP server\n");
+ LogPrint(BCLog::HTTP, "Interrupting HTTP server\n");
if (eventHTTP) {
// Unlisten sockets
for (evhttp_bound_socket *socket : boundSockets) {
evhttp_del_accept_socket(eventHTTP, socket);
}
// Reject requests on current connections
- evhttp_set_gencb(eventHTTP, http_reject_request_cb, NULL);
+ evhttp_set_gencb(eventHTTP, http_reject_request_cb, nullptr);
}
if (workQueue)
workQueue->Interrupt();
@@ -477,14 +472,15 @@ void InterruptHTTPServer()
void StopHTTPServer()
{
- LogPrint("http", "Stopping HTTP server\n");
+ LogPrint(BCLog::HTTP, "Stopping HTTP server\n");
if (workQueue) {
- LogPrint("http", "Waiting for HTTP worker threads to exit\n");
+ LogPrint(BCLog::HTTP, "Waiting for HTTP worker threads to exit\n");
workQueue->WaitExit();
delete workQueue;
+ workQueue = nullptr;
}
if (eventBase) {
- LogPrint("http", "Waiting for HTTP event thread to exit\n");
+ LogPrint(BCLog::HTTP, "Waiting for HTTP event thread to exit\n");
// Give event loop a few seconds to exit (to send back last RPC responses), then break it
// Before this was solved with event_base_loopexit, but that didn't work as expected in
// at least libevent 2.0.21 and always introduced a delay. In libevent
@@ -499,13 +495,13 @@ void StopHTTPServer()
}
if (eventHTTP) {
evhttp_free(eventHTTP);
- eventHTTP = 0;
+ eventHTTP = nullptr;
}
if (eventBase) {
event_base_free(eventBase);
- eventBase = 0;
+ eventBase = nullptr;
}
- LogPrint("http", "Stopped HTTP server\n");
+ LogPrint(BCLog::HTTP, "Stopped HTTP server\n");
}
struct event_base* EventBase()
@@ -534,7 +530,7 @@ HTTPEvent::~HTTPEvent()
}
void HTTPEvent::trigger(struct timeval* tv)
{
- if (tv == NULL)
+ if (tv == nullptr)
event_active(ev, 0, 0); // immediately trigger event in main thread
else
evtimer_add(ev, tv); // trigger after timeval passed
@@ -577,7 +573,7 @@ std::string HTTPRequest::ReadBody()
* 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
+ if (!data) // returns nullptr in case of empty buffer
return "";
std::string rv(data, size);
evbuffer_drain(buf, size);
@@ -604,10 +600,10 @@ void HTTPRequest::WriteReply(int nStatus, const std::string& strReply)
assert(evb);
evbuffer_add(evb, strReply.data(), strReply.size());
HTTPEvent* ev = new HTTPEvent(eventBase, true,
- std::bind(evhttp_send_reply, req, nStatus, (const char*)NULL, (struct evbuffer *)NULL));
- ev->trigger(0);
+ std::bind(evhttp_send_reply, req, nStatus, (const char*)nullptr, (struct evbuffer *)nullptr));
+ ev->trigger(nullptr);
replySent = true;
- req = 0; // transferred back to main thread
+ req = nullptr; // transferred back to main thread
}
CService HTTPRequest::GetPeer()
@@ -652,7 +648,7 @@ HTTPRequest::RequestMethod HTTPRequest::GetRequestMethod()
void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)
{
- LogPrint("http", "Registering HTTP handler for %s (exactmatch %d)\n", prefix, exactMatch);
+ LogPrint(BCLog::HTTP, "Registering HTTP handler for %s (exactmatch %d)\n", prefix, exactMatch);
pathHandlers.push_back(HTTPPathHandler(prefix, exactMatch, handler));
}
@@ -665,8 +661,19 @@ void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
break;
if (i != iend)
{
- LogPrint("http", "Unregistering HTTP handler for %s (exactmatch %d)\n", prefix, exactMatch);
+ LogPrint(BCLog::HTTP, "Unregistering HTTP handler for %s (exactmatch %d)\n", prefix, exactMatch);
pathHandlers.erase(i);
}
}
+std::string urlDecode(const std::string &urlEncoded) {
+ std::string res;
+ if (!urlEncoded.empty()) {
+ char *decoded = evhttp_uridecode(urlEncoded.c_str(), false, nullptr);
+ if (decoded) {
+ res = std::string(decoded);
+ free(decoded);
+ }
+ }
+ return res;
+}
diff --git a/src/httpserver.h b/src/httpserver.h
index b55b253bea..91ce5b4e00 100644
--- a/src/httpserver.h
+++ b/src/httpserver.h
@@ -32,6 +32,10 @@ void InterruptHTTPServer();
/** Stop HTTP server */
void StopHTTPServer();
+/** Change logging level for libevent. Removes BCLog::LIBEVENT from logCategories if
+ * libevent doesn't support debug logging.*/
+bool UpdateHTTPServerLogging(bool enable);
+
/** Handler for requests to a certain HTTP path */
typedef std::function<bool(HTTPRequest* req, const std::string &)> HTTPRequestHandler;
/** Register handler for prefix.
@@ -57,7 +61,7 @@ private:
bool replySent;
public:
- HTTPRequest(struct evhttp_request* req);
+ explicit HTTPRequest(struct evhttp_request* req);
~HTTPRequest();
enum RequestMethod {
@@ -82,7 +86,7 @@ public:
/**
* Get the request header specified by hdr, or an empty string.
- * Return an pair (isPresent,string).
+ * Return a pair (isPresent,string).
*/
std::pair<bool, std::string> GetHeader(const std::string& hdr);
@@ -121,7 +125,7 @@ public:
virtual ~HTTPClosure() {}
};
-/** Event class. This can be used either as an cross-thread trigger or as a timer.
+/** Event class. This can be used either as a cross-thread trigger or as a timer.
*/
class HTTPEvent
{
@@ -144,4 +148,6 @@ private:
struct event* ev;
};
+std::string urlDecode(const std::string &urlEncoded);
+
#endif // BITCOIN_HTTPSERVER_H
diff --git a/src/init.cpp b/src/init.cpp
index 14c0a36f52..539adc23d5 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -16,6 +16,7 @@
#include "checkpoints.h"
#include "compat/sanity.h"
#include "consensus/validation.h"
+#include "fs.h"
#include "httpserver.h"
#include "httprpc.h"
#include "key.h"
@@ -24,9 +25,13 @@
#include "netbase.h"
#include "net.h"
#include "net_processing.h"
+#include "policy/feerate.h"
+#include "policy/fees.h"
#include "policy/policy.h"
#include "rpc/server.h"
#include "rpc/register.h"
+#include "rpc/safemode.h"
+#include "rpc/blockchain.h"
#include "script/standard.h"
#include "script/sigcache.h"
#include "scheduler.h"
@@ -39,7 +44,7 @@
#include "utilmoneystr.h"
#include "validationinterface.h"
#ifdef ENABLE_WALLET
-#include "wallet/wallet.h"
+#include "wallet/init.h"
#endif
#include "warnings.h"
#include <stdint.h>
@@ -51,12 +56,9 @@
#endif
#include <boost/algorithm/string/classification.hpp>
-#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/split.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>
@@ -65,19 +67,16 @@
#include "zmq/zmqnotificationinterface.h"
#endif
-using namespace std;
-
bool fFeeEstimatesInitialized = false;
static const bool DEFAULT_PROXYRANDOMIZE = true;
static const bool DEFAULT_REST_ENABLE = false;
-static const bool DEFAULT_DISABLE_SAFEMODE = false;
static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false;
std::unique_ptr<CConnman> g_connman;
std::unique_ptr<PeerLogicValidation> peerLogic;
#if ENABLE_ZMQ
-static CZMQNotificationInterface* pzmqNotificationInterface = NULL;
+static CZMQNotificationInterface* pzmqNotificationInterface = nullptr;
#endif
#ifdef WIN32
@@ -89,14 +88,6 @@ static CZMQNotificationInterface* pzmqNotificationInterface = NULL;
#define MIN_CORE_FILEDESCRIPTORS 150
#endif
-/** Used to pass flags to the Bind() function */
-enum BindFlags {
- BF_NONE = 0,
- BF_EXPLICIT = (1U << 0),
- BF_REPORT_ERROR = (1U << 1),
- BF_WHITELIST = (1U << 2),
-};
-
static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat";
//////////////////////////////////////////////////////////////////////////////
@@ -111,19 +102,14 @@ static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat";
// created by AppInit() or the Qt main() function.
//
// A clean exit happens when StartShutdown() or the SIGTERM
-// signal handler sets fRequestShutdown, which triggers
-// the DetectShutdownThread(), which interrupts the main thread group.
-// DetectShutdownThread() then exits, which causes AppInit() to
-// continue (it .joins the shutdown thread).
-// Shutdown() is then
-// called to clean up database connections, and stop other
+// signal handler sets fRequestShutdown, which makes main thread's
+// WaitForShutdown() interrupts the thread group.
+// And then, WaitForShutdown() makes all other on-going threads
+// in the thread group join the main thread.
+// Shutdown() is then called to clean up database connections, and stop other
// threads that should only be stopped after the main network-processing
// threads have exited.
//
-// Note that if running -daemon the parent process returns from AppInit2
-// before adding any threads to the threadGroup, so .join_all() returns
-// immediately and the parent exits from main().
-//
// Shutdown for Qt is very similar, only it uses a QTimer to detect
// fRequestShutdown getting set, and then does the normal Qt
// shutdown thing.
@@ -146,13 +132,13 @@ bool ShutdownRequested()
* chainstate, while keeping user interface out of the common library, which is shared
* between bitcoind, and bitcoin-qt and non-server tools.
*/
-class CCoinsViewErrorCatcher : public CCoinsViewBacked
+class CCoinsViewErrorCatcher final : public CCoinsViewBacked
{
public:
- CCoinsViewErrorCatcher(CCoinsView* view) : CCoinsViewBacked(view) {}
- bool GetCoins(const uint256 &txid, CCoins &coins) const {
+ explicit CCoinsViewErrorCatcher(CCoinsView* view) : CCoinsViewBacked(view) {}
+ bool GetCoin(const COutPoint &outpoint, Coin &coin) const override {
try {
- return CCoinsViewBacked::GetCoins(txid, coins);
+ return CCoinsViewBacked::GetCoin(outpoint, coin);
} catch(const std::runtime_error& e) {
uiInterface.ThreadSafeMessageBox(_("Error reading from database, shutting down."), "", CClientUIInterface::MSG_ERROR);
LogPrintf("Error reading from database: %s\n", e.what());
@@ -166,8 +152,7 @@ public:
// Writes do not need similar protection, as failure to write is handled by the caller.
};
-static CCoinsViewDB *pcoinsdbview = NULL;
-static CCoinsViewErrorCatcher *pcoinscatcher = NULL;
+static CCoinsViewErrorCatcher *pcoinscatcher = nullptr;
static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle;
void Interrupt(boost::thread_group& threadGroup)
@@ -190,7 +175,7 @@ void Shutdown()
if (!lockShutdown)
return;
- /// Note: Shutdown() must be able to handle cases in which AppInit2() failed part of the way,
+ /// Note: Shutdown() must be able to handle cases in which initialization failed part of the way,
/// for example if the data directory was found to be locked.
/// Be sure that anything that writes files or flushes caches only does this if the respective
/// module was initialized.
@@ -202,68 +187,86 @@ void Shutdown()
StopRPC();
StopHTTPServer();
#ifdef ENABLE_WALLET
- if (pwalletMain)
- pwalletMain->Flush(false);
+ FlushWallets();
#endif
MapPort(false);
+
+ // Because these depend on each-other, we make sure that neither can be
+ // using the other before destroying them.
UnregisterValidationInterface(peerLogic.get());
+ if(g_connman) g_connman->Stop();
peerLogic.reset();
g_connman.reset();
StopTorControl();
- UnregisterNodeSignals(GetNodeSignals());
- if (fDumpMempoolLater)
+ if (fDumpMempoolLater && gArgs.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
DumpMempool();
+ }
if (fFeeEstimatesInitialized)
{
- boost::filesystem::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME;
- CAutoFile est_fileout(fopen(est_path.string().c_str(), "wb"), SER_DISK, CLIENT_VERSION);
+ ::feeEstimator.FlushUnconfirmed(::mempool);
+ fs::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME;
+ CAutoFile est_fileout(fsbridge::fopen(est_path, "wb"), SER_DISK, CLIENT_VERSION);
if (!est_fileout.IsNull())
- mempool.WriteFeeEstimates(est_fileout);
+ ::feeEstimator.Write(est_fileout);
else
LogPrintf("%s: Failed to write fee estimates to %s\n", __func__, est_path.string());
fFeeEstimatesInitialized = false;
}
+ // FlushStateToDisk generates a SetBestChain callback, which we should avoid missing
+ if (pcoinsTip != nullptr) {
+ FlushStateToDisk();
+ }
+
+ // After there are no more peers/RPC left to give us new data which may generate
+ // CValidationInterface callbacks, flush them...
+ GetMainSignals().FlushBackgroundCallbacks();
+
+ // Any future callbacks will be dropped. This should absolutely be safe - if
+ // missing a callback results in an unrecoverable situation, unclean shutdown
+ // would too. The only reason to do the above flushes is to let the wallet catch
+ // up with our current chain to avoid any strange pruning edge cases and make
+ // next startup faster by avoiding rescan.
+
{
LOCK(cs_main);
- if (pcoinsTip != NULL) {
+ if (pcoinsTip != nullptr) {
FlushStateToDisk();
}
delete pcoinsTip;
- pcoinsTip = NULL;
+ pcoinsTip = nullptr;
delete pcoinscatcher;
- pcoinscatcher = NULL;
+ pcoinscatcher = nullptr;
delete pcoinsdbview;
- pcoinsdbview = NULL;
+ pcoinsdbview = nullptr;
delete pblocktree;
- pblocktree = NULL;
+ pblocktree = nullptr;
}
#ifdef ENABLE_WALLET
- if (pwalletMain)
- pwalletMain->Flush(true);
+ StopWallets();
#endif
#if ENABLE_ZMQ
if (pzmqNotificationInterface) {
UnregisterValidationInterface(pzmqNotificationInterface);
delete pzmqNotificationInterface;
- pzmqNotificationInterface = NULL;
+ pzmqNotificationInterface = nullptr;
}
#endif
#ifndef WIN32
try {
- boost::filesystem::remove(GetPidFile());
- } catch (const boost::filesystem::filesystem_error& e) {
+ fs::remove(GetPidFile());
+ } catch (const fs::filesystem_error& e) {
LogPrintf("%s: Unable to remove pidfile: %s\n", __func__, e.what());
}
#endif
UnregisterAllValidationInterfaces();
+ GetMainSignals().UnregisterBackgroundSignalScheduler();
#ifdef ENABLE_WALLET
- delete pwalletMain;
- pwalletMain = NULL;
+ CloseWallets();
#endif
globalVerifyHandle.reset();
ECC_Stop();
@@ -271,29 +274,31 @@ void Shutdown()
}
/**
- * Signal handlers are very limited in what they are allowed to do, so:
+ * Signal handlers are very limited in what they are allowed to do.
+ * The execution context the handler is invoked in is not guaranteed,
+ * so we restrict handler operations to just touching variables:
*/
-void HandleSIGTERM(int)
+static void HandleSIGTERM(int)
{
fRequestShutdown = true;
}
-void HandleSIGHUP(int)
+static void HandleSIGHUP(int)
{
fReopenDebugLog = true;
}
-bool static Bind(CConnman& connman, const CService &addr, unsigned int flags) {
- if (!(flags & BF_EXPLICIT) && IsLimited(addr))
- return false;
- std::string strError;
- if (!connman.BindListenPort(addr, strError, (flags & BF_WHITELIST) != 0)) {
- if (flags & BF_REPORT_ERROR)
- return InitError(strError);
- return false;
- }
- return true;
+#ifndef WIN32
+static void registerSignalHandler(int signal, void(*handler)(int))
+{
+ struct sigaction sa;
+ sa.sa_handler = handler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sigaction(signal, &sa, nullptr);
}
+#endif
+
void OnRPCStarted()
{
uiInterface.NotifyBlockTip.connect(&RPCNotifyBlockChange);
@@ -304,32 +309,27 @@ void OnRPCStopped()
uiInterface.NotifyBlockTip.disconnect(&RPCNotifyBlockChange);
RPCNotifyBlockChange(false, nullptr);
cvBlockChange.notify_all();
- LogPrint("rpc", "RPC stopped.\n");
-}
-
-void OnRPCPreCommand(const CRPCCommand& cmd)
-{
- // Observe safe mode
- string strWarning = GetWarnings("rpc");
- if (strWarning != "" && !GetBoolArg("-disablesafemode", DEFAULT_DISABLE_SAFEMODE) &&
- !cmd.okSafeMode)
- throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, string("Safe mode: ") + strWarning);
+ LogPrint(BCLog::RPC, "RPC stopped.\n");
}
std::string HelpMessage(HelpMessageMode mode)
{
- const bool showDebug = GetBoolArg("-help-debug", false);
+ const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN);
+ const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET);
+ const auto defaultChainParams = CreateChainParams(CBaseChainParams::MAIN);
+ const auto testnetChainParams = CreateChainParams(CBaseChainParams::TESTNET);
+ const bool showDebug = gArgs.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:"));
+ std::string strUsage = HelpMessageGroup(_("Options:"));
strUsage += HelpMessageOpt("-?", _("Print this help message and exit"));
strUsage += HelpMessageOpt("-version", _("Print version and exit"));
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)"));
if (showDebug)
strUsage += HelpMessageOpt("-blocksonly", strprintf(_("Whether to operate in a blocks only mode (default: %u)"), DEFAULT_BLOCKSONLY));
- strUsage +=HelpMessageOpt("-assumevalid=<hex>", strprintf(_("If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)"), Params(CBaseChainParams::MAIN).GetConsensus().defaultAssumeValid.GetHex(), Params(CBaseChainParams::TESTNET).GetConsensus().defaultAssumeValid.GetHex()));
+ strUsage +=HelpMessageOpt("-assumevalid=<hex>", strprintf(_("If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)"), defaultChainParams->GetConsensus().defaultAssumeValid.GetHex(), testnetChainParams->GetConsensus().defaultAssumeValid.GetHex()));
strUsage += HelpMessageOpt("-conf=<file>", strprintf(_("Specify configuration file (default: %s)"), BITCOIN_CONF_FILENAME));
if (mode == HMM_BITCOIND)
{
@@ -338,6 +338,9 @@ std::string HelpMessage(HelpMessageMode mode)
#endif
}
strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory"));
+ if (showDebug) {
+ strUsage += HelpMessageOpt("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize));
+ }
strUsage += HelpMessageOpt("-dbcache=<n>", strprintf(_("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache));
if (showDebug)
strUsage += HelpMessageOpt("-feefilter", strprintf("Tell other nodes to filter invs to us by our mempool min fee (default: %u)", DEFAULT_FEEFILTER));
@@ -345,6 +348,11 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS));
strUsage += HelpMessageOpt("-maxmempool=<n>", strprintf(_("Keep the transaction memory pool below <n> megabytes (default: %u)"), DEFAULT_MAX_MEMPOOL_SIZE));
strUsage += HelpMessageOpt("-mempoolexpiry=<n>", strprintf(_("Do not keep transactions in the mempool longer than <n> hours (default: %u)"), DEFAULT_MEMPOOL_EXPIRY));
+ if (showDebug) {
+ strUsage += HelpMessageOpt("-minimumchainwork=<hex>", strprintf("Minimum work assumed to exist on a valid chain in hex (default: %s, testnet: %s)", defaultChainParams->GetConsensus().nMinimumChainWork.GetHex(), testnetChainParams->GetConsensus().nMinimumChainWork.GetHex()));
+ }
+ strUsage += HelpMessageOpt("-persistmempool", strprintf(_("Whether to save the mempool on shutdown and load on restart (default: %u)"), DEFAULT_PERSIST_MEMPOOL));
+ strUsage += HelpMessageOpt("-blockreconstructionextratxn=<n>", strprintf(_("Extra transactions to keep in memory for compact block reconstructions (default: %u)"), DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN));
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)"),
-GetNumCores(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS));
#ifndef WIN32
@@ -365,13 +373,13 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-banscore=<n>", strprintf(_("Threshold for disconnecting misbehaving peers (default: %u)"), DEFAULT_BANSCORE_THRESHOLD));
strUsage += HelpMessageOpt("-bantime=<n>", strprintf(_("Number of seconds to keep misbehaving peers from reconnecting (default: %u)"), DEFAULT_MISBEHAVING_BANTIME));
strUsage += HelpMessageOpt("-bind=<addr>", _("Bind to given address and always listen on it. Use [host]:port notation for IPv6"));
- strUsage += HelpMessageOpt("-connect=<ip>", _("Connect only to the specified node(s); -noconnect or -connect=0 alone to disable automatic connections"));
+ strUsage += HelpMessageOpt("-connect=<ip>", _("Connect only to the specified node(s); -connect=0 disables automatic connections"));
strUsage += HelpMessageOpt("-discover", _("Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)"));
strUsage += HelpMessageOpt("-dns", _("Allow DNS lookups for -addnode, -seednode and -connect") + " " + strprintf(_("(default: %u)"), DEFAULT_NAME_LOOKUP));
- strUsage += HelpMessageOpt("-dnsseed", _("Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect/-noconnect)"));
+ strUsage += HelpMessageOpt("-dnsseed", _("Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect used)"));
strUsage += HelpMessageOpt("-externalip=<ip>", _("Specify your own public address"));
strUsage += HelpMessageOpt("-forcednsseed", strprintf(_("Always query for peer addresses via DNS lookup (default: %u)"), DEFAULT_FORCEDNSSEED));
- strUsage += HelpMessageOpt("-listen", _("Accept connections from outside (default: 1 if no -proxy or -connect/-noconnect)"));
+ strUsage += HelpMessageOpt("-listen", _("Accept connections from outside (default: 1 if no -proxy or -connect)"));
strUsage += HelpMessageOpt("-listenonion", strprintf(_("Automatically create Tor hidden service (default: %d)"), DEFAULT_LISTEN_ONION));
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)"), DEFAULT_MAXRECEIVEBUFFER));
@@ -381,10 +389,9 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-onlynet=<net>", _("Only connect to nodes in network <net> (ipv4, ipv6 or onion)"));
strUsage += HelpMessageOpt("-permitbaremultisig", strprintf(_("Relay non-P2SH multisig (default: %u)"), DEFAULT_PERMIT_BAREMULTISIG));
strUsage += HelpMessageOpt("-peerbloomfilters", strprintf(_("Support filtering of blocks and transaction with bloom filters (default: %u)"), DEFAULT_PEERBLOOMFILTERS));
- strUsage += HelpMessageOpt("-port=<port>", strprintf(_("Listen for connections on <port> (default: %u or testnet: %u)"), Params(CBaseChainParams::MAIN).GetDefaultPort(), Params(CBaseChainParams::TESTNET).GetDefaultPort()));
+ strUsage += HelpMessageOpt("-port=<port>", strprintf(_("Listen for connections on <port> (default: %u or testnet: %u)"), defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort()));
strUsage += HelpMessageOpt("-proxy=<ip:port>", _("Connect through SOCKS5 proxy"));
strUsage += HelpMessageOpt("-proxyrandomize", strprintf(_("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)"), DEFAULT_PROXYRANDOMIZE));
- strUsage += HelpMessageOpt("-rpcserialversion", strprintf(_("Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(1) (default: %d)"), DEFAULT_RPC_SERIALIZE_VERSION));
strUsage += HelpMessageOpt("-seednode=<ip>", _("Connect to a node to retrieve peer addresses, and disconnect"));
strUsage += HelpMessageOpt("-timeout=<n>", strprintf(_("Specify connection timeout in milliseconds (minimum: 1, default: %d)"), DEFAULT_CONNECT_TIMEOUT));
strUsage += HelpMessageOpt("-torcontrol=<ip>:<port>", strprintf(_("Tor control port to use if onion listening enabled (default: %s)"), DEFAULT_TOR_CONTROL));
@@ -399,12 +406,10 @@ 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=<IP address or network>", _("Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR notated network (e.g. 1.2.3.0/24). 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"));
- strUsage += HelpMessageOpt("-whitelistrelay", strprintf(_("Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)"), DEFAULT_WHITELISTRELAY));
- strUsage += HelpMessageOpt("-whitelistforcerelay", strprintf(_("Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)"), DEFAULT_WHITELISTFORCERELAY));
strUsage += HelpMessageOpt("-maxuploadtarget=<n>", strprintf(_("Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)"), DEFAULT_MAX_UPLOAD_TARGET));
#ifdef ENABLE_WALLET
- strUsage += CWallet::GetWalletHelpString(showDebug);
+ strUsage += GetWalletHelpString(showDebug);
#endif
#if ENABLE_ZMQ
@@ -421,27 +426,26 @@ std::string HelpMessage(HelpMessageMode mode)
{
strUsage += HelpMessageOpt("-checkblocks=<n>", strprintf(_("How many blocks to check at startup (default: %u, 0 = all)"), DEFAULT_CHECKBLOCKS));
strUsage += HelpMessageOpt("-checklevel=<n>", strprintf(_("How thorough the block verification of -checkblocks is (0-4, default: %u)"), DEFAULT_CHECKLEVEL));
- strUsage += HelpMessageOpt("-checkblockindex", strprintf("Do a full consistency check for mapBlockIndex, setBlockIndexCandidates, chainActive and mapBlocksUnlinked occasionally. Also sets -checkmempool (default: %u)", Params(CBaseChainParams::MAIN).DefaultConsistencyChecks()));
- strUsage += HelpMessageOpt("-checkmempool=<n>", strprintf("Run checks every <n> transactions (default: %u)", Params(CBaseChainParams::MAIN).DefaultConsistencyChecks()));
+ strUsage += HelpMessageOpt("-checkblockindex", strprintf("Do a full consistency check for mapBlockIndex, setBlockIndexCandidates, chainActive and mapBlocksUnlinked occasionally. Also sets -checkmempool (default: %u)", defaultChainParams->DefaultConsistencyChecks()));
+ strUsage += HelpMessageOpt("-checkmempool=<n>", strprintf("Run checks every <n> transactions (default: %u)", defaultChainParams->DefaultConsistencyChecks()));
strUsage += HelpMessageOpt("-checkpoints", strprintf("Disable expensive verification for known chain history (default: %u)", DEFAULT_CHECKPOINTS_ENABLED));
strUsage += HelpMessageOpt("-disablesafemode", strprintf("Disable safemode, override a real safe mode event (default: %u)", DEFAULT_DISABLE_SAFEMODE));
+ strUsage += HelpMessageOpt("-deprecatedrpc=<method>", "Allows deprecated RPC method(s) to be used");
strUsage += HelpMessageOpt("-testsafemode", strprintf("Force safe mode (default: %u)", DEFAULT_TESTSAFEMODE));
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("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", DEFAULT_STOPAFTERBLOCKIMPORT));
+ strUsage += HelpMessageOpt("-stopatheight", strprintf("Stop running after reaching the given height in the main chain (default: %u)", DEFAULT_STOPATHEIGHT));
+
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));
- strUsage += HelpMessageOpt("-bip9params=deployment:start:end", "Use given start/end times for specified BIP9 deployment (regtest-only)");
+ strUsage += HelpMessageOpt("-vbparams=deployment:start:end", "Use given start/end times for specified version bits deployment (regtest-only)");
}
- string debugCategories = "addrman, alert, bench, cmpctblock, coindb, db, http, libevent, lock, mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc, selectcoins, tor, zmq"; // Don't translate these and qt below
- if (mode == HMM_BITCOIN_QT)
- debugCategories += ", qt";
strUsage += HelpMessageOpt("-debug=<category>", strprintf(_("Output debugging information (default: %u, supplying <category> is optional)"), 0) + ". " +
- _("If <category> is not supplied or if <category> = 1, output all debugging information.") + _("<category> can be:") + " " + debugCategories + ".");
- if (showDebug)
- strUsage += HelpMessageOpt("-nodebug", "Turn off debugging messages, same as -debug=0");
+ _("If <category> is not supplied or if <category> = 1, output all debugging information.") + " " + _("<category> can be:") + " " + ListLogCategories() + ".");
+ strUsage += HelpMessageOpt("-debugexclude=<category>", strprintf(_("Exclude debugging information for a category. Can be used in conjunction with -debug=1 to output debug logs for all categories except one or more specified categories.")));
strUsage += HelpMessageOpt("-help-debug", _("Show all debugging options (usage: --help -help-debug)"));
strUsage += HelpMessageOpt("-logips", strprintf(_("Include IP addresses in debug output (default: %u)"), DEFAULT_LOGIPS));
strUsage += HelpMessageOpt("-logtimestamps", strprintf(_("Prepend debug output with timestamp (default: %u)"), DEFAULT_LOGTIMESTAMPS));
@@ -449,19 +453,15 @@ std::string HelpMessage(HelpMessageMode mode)
{
strUsage += HelpMessageOpt("-logtimemicros", strprintf("Add microsecond precision to debug timestamps (default: %u)", DEFAULT_LOGTIMEMICROS));
strUsage += HelpMessageOpt("-mocktime=<n>", "Replace actual time with <n> seconds since epoch (default: 0)");
- strUsage += HelpMessageOpt("-limitfreerelay=<n>", strprintf("Continuously rate-limit free transactions to <n>*1000 bytes per minute (default: %u)", DEFAULT_LIMITFREERELAY));
- strUsage += HelpMessageOpt("-relaypriority", strprintf("Require high priority for relaying free or low-fee transactions (default: %u)", DEFAULT_RELAYPRIORITY));
- strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf("Limit size of signature cache to <n> MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_SIZE));
+ strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf("Limit sum of signature cache and script execution cache sizes to <n> MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_SIZE));
strUsage += HelpMessageOpt("-maxtipage=<n>", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE));
}
- strUsage += HelpMessageOpt("-minrelaytxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)"),
- CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE)));
strUsage += HelpMessageOpt("-maxtxfee=<amt>", strprintf(_("Maximum total fees (in %s) to use in a single wallet transaction or raw transaction; setting this too low may abort large transactions (default: %s)"),
CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MAXFEE)));
strUsage += HelpMessageOpt("-printtoconsole", _("Send trace/debug info to console instead of debug.log file"));
if (showDebug)
{
- strUsage += HelpMessageOpt("-printpriority", strprintf("Log transaction priority and fee per kB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY));
+ strUsage += HelpMessageOpt("-printpriority", strprintf("Log transaction fee per kB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY));
}
strUsage += HelpMessageOpt("-shrinkdebugfile", _("Shrink debug.log file on client startup (default: 1 when no -debug)"));
@@ -469,19 +469,22 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageGroup(_("Node relay options:"));
if (showDebug) {
- strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !Params(CBaseChainParams::TESTNET).RequireStandard()));
+ strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !testnetChainParams->RequireStandard()));
strUsage += HelpMessageOpt("-incrementalrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to define cost of relay, used for mempool limiting and BIP 125 replacement. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_INCREMENTAL_RELAY_FEE)));
- strUsage += HelpMessageOpt("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to defined dust, the value of an output such that it will cost about 1/3 of its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)));
+ strUsage += HelpMessageOpt("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to defined dust, the value of an output such that it will cost more than its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)));
}
strUsage += HelpMessageOpt("-bytespersigop", strprintf(_("Equivalent bytes per sigop in transactions for relay and mining (default: %u)"), DEFAULT_BYTES_PER_SIGOP));
strUsage += HelpMessageOpt("-datacarrier", strprintf(_("Relay and mine data carrier transactions (default: %u)"), DEFAULT_ACCEPT_DATACARRIER));
strUsage += HelpMessageOpt("-datacarriersize", strprintf(_("Maximum size of data in data carrier transactions we relay and mine (default: %u)"), MAX_OP_RETURN_RELAY));
strUsage += HelpMessageOpt("-mempoolreplacement", strprintf(_("Enable transaction replacement in the memory pool (default: %u)"), DEFAULT_ENABLE_REPLACEMENT));
+ strUsage += HelpMessageOpt("-minrelaytxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)"),
+ CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE)));
+ strUsage += HelpMessageOpt("-whitelistrelay", strprintf(_("Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)"), DEFAULT_WHITELISTRELAY));
+ strUsage += HelpMessageOpt("-whitelistforcerelay", strprintf(_("Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)"), DEFAULT_WHITELISTFORCERELAY));
strUsage += HelpMessageGroup(_("Block creation options:"));
strUsage += HelpMessageOpt("-blockmaxweight=<n>", strprintf(_("Set maximum BIP141 block weight (default: %d)"), DEFAULT_BLOCK_MAX_WEIGHT));
- 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));
+ strUsage += HelpMessageOpt("-blockmaxsize=<n>", _("Set maximum BIP141 block weight to this * 4. Deprecated, use blockmaxweight"));
strUsage += HelpMessageOpt("-blockmintxfee=<amt>", strprintf(_("Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)"), CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE)));
if (showDebug)
strUsage += HelpMessageOpt("-blockversion=<n>", "Override block version to test forking scenarios");
@@ -489,13 +492,14 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageGroup(_("RPC server options:"));
strUsage += HelpMessageOpt("-server", _("Accept command line and JSON-RPC commands"));
strUsage += HelpMessageOpt("-rest", strprintf(_("Accept public REST requests (default: %u)"), DEFAULT_REST_ENABLE));
- strUsage += HelpMessageOpt("-rpcbind=<addr>", _("Bind to given address to listen for JSON-RPC connections. Use [host]:port notation for IPv6. This option can be specified multiple times (default: bind to all interfaces)"));
+ strUsage += HelpMessageOpt("-rpcbind=<addr>[:port]", _("Bind to given address to listen for JSON-RPC connections. This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost, or if -rpcallowip has been specified, 0.0.0.0 and :: i.e., all addresses)"));
strUsage += HelpMessageOpt("-rpccookiefile=<loc>", _("Location of the auth cookie (default: data dir)"));
strUsage += HelpMessageOpt("-rpcuser=<user>", _("Username for JSON-RPC connections"));
strUsage += HelpMessageOpt("-rpcpassword=<pw>", _("Password for JSON-RPC connections"));
strUsage += HelpMessageOpt("-rpcauth=<userpw>", _("Username and hashed password for JSON-RPC connections. The field <userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=<USERNAME>/rpcpassword=<PASSWORD> pair of arguments. This option can be specified multiple times"));
- strUsage += HelpMessageOpt("-rpcport=<port>", strprintf(_("Listen for JSON-RPC connections on <port> (default: %u or testnet: %u)"), BaseParams(CBaseChainParams::MAIN).RPCPort(), BaseParams(CBaseChainParams::TESTNET).RPCPort()));
+ strUsage += HelpMessageOpt("-rpcport=<port>", strprintf(_("Listen for JSON-RPC connections on <port> (default: %u or testnet: %u)"), defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort()));
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("-rpcserialversion", strprintf(_("Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(1) (default: %d)"), DEFAULT_RPC_SERIALIZE_VERSION));
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));
@@ -532,10 +536,11 @@ static void BlockNotifyCallback(bool initialSync, const CBlockIndex *pBlockIndex
if (initialSync || !pBlockIndex)
return;
- std::string strCmd = GetArg("-blocknotify", "");
-
- boost::replace_all(strCmd, "%s", pBlockIndex->GetBlockHash().GetHex());
- boost::thread t(runCommand, strCmd); // thread runs free
+ std::string strCmd = gArgs.GetArg("-blocknotify", "");
+ if (!strCmd.empty()) {
+ boost::replace_all(strCmd, "%s", pBlockIndex->GetBlockHash().GetHex());
+ boost::thread t(runCommand, strCmd); // thread runs free
+ }
}
static bool fHaveGenesis = false;
@@ -544,7 +549,7 @@ static CConditionVariable condvar_GenesisWait;
static void BlockNotifyGenesisWait(bool, const CBlockIndex *pBlockIndex)
{
- if (pBlockIndex != NULL) {
+ if (pBlockIndex != nullptr) {
{
boost::unique_lock<boost::mutex> lock_GenesisWait(cs_GenesisWait);
fHaveGenesis = true;
@@ -575,15 +580,14 @@ struct CImportingNow
// works correctly.
void CleanupBlockRevFiles()
{
- using namespace boost::filesystem;
- map<string, path> mapBlockFiles;
+ std::map<std::string, fs::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++) {
+ fs::path blocksdir = GetDataDir() / "blocks";
+ for (fs::directory_iterator it(blocksdir); it != fs::directory_iterator(); it++) {
if (is_regular_file(*it) &&
it->path().filename().string().length() == 12 &&
it->path().filename().string().substr(8,4) == ".dat")
@@ -600,7 +604,7 @@ void CleanupBlockRevFiles()
// 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) {
+ for (const std::pair<std::string, fs::path>& item : mapBlockFiles) {
if (atoi(item.first) == nContigCounter) {
nContigCounter++;
continue;
@@ -609,7 +613,7 @@ void CleanupBlockRevFiles()
}
}
-void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
+void ThreadImport(std::vector<fs::path> vImportFiles)
{
const CChainParams& chainparams = Params();
RenameThread("bitcoin-loadblk");
@@ -622,7 +626,7 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
int nFile = 0;
while (true) {
CDiskBlockPos pos(nFile, 0);
- if (!boost::filesystem::exists(GetBlockPosFilename(pos, "blk")))
+ if (!fs::exists(GetBlockPosFilename(pos, "blk")))
break; // No block files left to reindex
FILE *file = OpenBlockFile(pos, true);
if (!file)
@@ -635,15 +639,15 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
fReindex = false;
LogPrintf("Reindexing finished\n");
// To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked):
- InitBlockIndex(chainparams);
+ LoadGenesisBlock(chainparams);
}
// hardcoded $DATADIR/bootstrap.dat
- boost::filesystem::path pathBootstrap = GetDataDir() / "bootstrap.dat";
- if (boost::filesystem::exists(pathBootstrap)) {
- FILE *file = fopen(pathBootstrap.string().c_str(), "rb");
+ fs::path pathBootstrap = GetDataDir() / "bootstrap.dat";
+ if (fs::exists(pathBootstrap)) {
+ FILE *file = fsbridge::fopen(pathBootstrap, "rb");
if (file) {
- boost::filesystem::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old";
+ fs::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old";
LogPrintf("Importing bootstrap.dat...\n");
LoadExternalBlockFile(chainparams, file);
RenameOver(pathBootstrap, pathBootstrapOld);
@@ -653,8 +657,8 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
}
// -loadblock=
- BOOST_FOREACH(const boost::filesystem::path& path, vImportFiles) {
- FILE *file = fopen(path.string().c_str(), "rb");
+ for (const fs::path& path : vImportFiles) {
+ FILE *file = fsbridge::fopen(path, "rb");
if (file) {
LogPrintf("Importing blocks file %s...\n", path.string());
LoadExternalBlockFile(chainparams, file);
@@ -670,13 +674,15 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
StartShutdown();
}
- if (GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) {
+ if (gArgs.GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) {
LogPrintf("Stopping after block import\n");
StartShutdown();
}
} // End scope of CImportingNow
- LoadMempool();
- fDumpMempoolLater = !fRequestShutdown;
+ if (gArgs.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
+ LoadMempool();
+ fDumpMempoolLater = !fRequestShutdown;
+ }
}
/** Sanity checks
@@ -689,9 +695,15 @@ bool InitSanityCheck(void)
InitError("Elliptic curve cryptography sanity check failure. Aborting.");
return false;
}
+
if (!glibc_sanity_test() || !glibcxx_sanity_test())
return false;
+ if (!Random_SanityCheck()) {
+ InitError("OS cryptographic RNG sanity check failure. Aborting.");
+ return false;
+ }
+
return true;
}
@@ -699,14 +711,13 @@ bool AppInitServers(boost::thread_group& threadGroup)
{
RPCServer::OnStarted(&OnRPCStarted);
RPCServer::OnStopped(&OnRPCStopped);
- RPCServer::OnPreCommand(&OnRPCPreCommand);
if (!InitHTTPServer())
return false;
if (!StartRPC())
return false;
if (!StartHTTPRPC())
return false;
- if (GetBoolArg("-rest", DEFAULT_REST_ENABLE) && !StartREST())
+ if (gArgs.GetBoolArg("-rest", DEFAULT_REST_ENABLE) && !StartREST())
return false;
if (!StartHTTPServer())
return false;
@@ -718,63 +729,72 @@ void InitParameterInteraction()
{
// when specifying an explicit binding address, you want to listen on it
// even when -connect or -proxy is specified
- if (IsArgSet("-bind")) {
- if (SoftSetBoolArg("-listen", true))
+ if (gArgs.IsArgSet("-bind")) {
+ if (gArgs.SoftSetBoolArg("-listen", true))
LogPrintf("%s: parameter interaction: -bind set -> setting -listen=1\n", __func__);
}
- if (IsArgSet("-whitebind")) {
- if (SoftSetBoolArg("-listen", true))
+ if (gArgs.IsArgSet("-whitebind")) {
+ if (gArgs.SoftSetBoolArg("-listen", true))
LogPrintf("%s: parameter interaction: -whitebind set -> setting -listen=1\n", __func__);
}
- if (mapMultiArgs.count("-connect") && mapMultiArgs.at("-connect").size() > 0) {
+ if (gArgs.IsArgSet("-connect")) {
// when only connecting to trusted nodes, do not seed via DNS, or listen by default
- if (SoftSetBoolArg("-dnsseed", false))
+ if (gArgs.SoftSetBoolArg("-dnsseed", false))
LogPrintf("%s: parameter interaction: -connect set -> setting -dnsseed=0\n", __func__);
- if (SoftSetBoolArg("-listen", false))
+ if (gArgs.SoftSetBoolArg("-listen", false))
LogPrintf("%s: parameter interaction: -connect set -> setting -listen=0\n", __func__);
}
- if (IsArgSet("-proxy")) {
+ if (gArgs.IsArgSet("-proxy")) {
// to protect privacy, do not listen by default if a default proxy server is specified
- if (SoftSetBoolArg("-listen", false))
+ if (gArgs.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))
+ if (gArgs.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))
+ if (gArgs.SoftSetBoolArg("-discover", false))
LogPrintf("%s: parameter interaction: -proxy set -> setting -discover=0\n", __func__);
}
- if (!GetBoolArg("-listen", DEFAULT_LISTEN)) {
+ if (!gArgs.GetBoolArg("-listen", DEFAULT_LISTEN)) {
// do not map ports or try to retrieve public IP when not listening (pointless)
- if (SoftSetBoolArg("-upnp", false))
+ if (gArgs.SoftSetBoolArg("-upnp", false))
LogPrintf("%s: parameter interaction: -listen=0 -> setting -upnp=0\n", __func__);
- if (SoftSetBoolArg("-discover", false))
+ if (gArgs.SoftSetBoolArg("-discover", false))
LogPrintf("%s: parameter interaction: -listen=0 -> setting -discover=0\n", __func__);
- if (SoftSetBoolArg("-listenonion", false))
+ if (gArgs.SoftSetBoolArg("-listenonion", false))
LogPrintf("%s: parameter interaction: -listen=0 -> setting -listenonion=0\n", __func__);
}
- if (IsArgSet("-externalip")) {
+ if (gArgs.IsArgSet("-externalip")) {
// if an explicit public IP is specified, do not try to find others
- if (SoftSetBoolArg("-discover", false))
+ if (gArgs.SoftSetBoolArg("-discover", false))
LogPrintf("%s: parameter interaction: -externalip set -> setting -discover=0\n", __func__);
}
// disable whitelistrelay in blocksonly mode
- if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)) {
- if (SoftSetBoolArg("-whitelistrelay", false))
+ if (gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)) {
+ if (gArgs.SoftSetBoolArg("-whitelistrelay", false))
LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -whitelistrelay=0\n", __func__);
}
// Forcing relay from whitelisted hosts implies we will accept relays from them in the first place.
- if (GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) {
- if (SoftSetBoolArg("-whitelistrelay", true))
+ if (gArgs.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) {
+ if (gArgs.SoftSetBoolArg("-whitelistrelay", true))
LogPrintf("%s: parameter interaction: -whitelistforcerelay=1 -> setting -whitelistrelay=1\n", __func__);
}
+
+ if (gArgs.IsArgSet("-blockmaxsize")) {
+ unsigned int max_size = gArgs.GetArg("-blockmaxsize", 0);
+ if (gArgs.SoftSetArg("blockmaxweight", strprintf("%d", max_size * WITNESS_SCALE_FACTOR))) {
+ LogPrintf("%s: parameter interaction: -blockmaxsize=%d -> setting -blockmaxweight=%d (-blockmaxsize is deprecated!)\n", __func__, max_size, max_size * WITNESS_SCALE_FACTOR);
+ } else {
+ LogPrintf("%s: Ignoring blockmaxsize setting which is overridden by blockmaxweight", __func__);
+ }
+ }
}
static std::string ResolveErrMsg(const char * const optname, const std::string& strBind)
@@ -784,10 +804,10 @@ static std::string ResolveErrMsg(const char * const optname, const std::string&
void InitLogging()
{
- fPrintToConsole = GetBoolArg("-printtoconsole", false);
- fLogTimestamps = GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS);
- fLogTimeMicros = GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS);
- fLogIPs = GetBoolArg("-logips", DEFAULT_LOGIPS);
+ fPrintToConsole = gArgs.GetBoolArg("-printtoconsole", false);
+ fLogTimestamps = gArgs.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS);
+ fLogTimeMicros = gArgs.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS);
+ fLogIPs = gArgs.GetBoolArg("-logips", DEFAULT_LOGIPS);
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\n", FormatFullVersion());
@@ -801,7 +821,20 @@ int nUserMaxConnections;
int nFD;
ServiceFlags nLocalServices = NODE_NETWORK;
-}
+} // namespace
+
+[[noreturn]] static void new_handler_terminate()
+{
+ // Rather than throwing std::bad-alloc if allocation fails, terminate
+ // immediately to (try to) avoid chain corruption.
+ // Since LogPrintf may itself allocate memory, set the handler directly
+ // to terminate first.
+ std::set_new_handler(std::terminate);
+ LogPrintf("Error: Out of memory. Terminating.\n");
+
+ // The log was successful, terminate now.
+ std::terminate();
+};
bool AppInitBasicSetup()
{
@@ -809,9 +842,7 @@ bool AppInitBasicSetup()
#ifdef _MSC_VER
// Turn off Microsoft heap dump noise
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
- _CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
-#endif
-#if _MSC_VER >= 1400
+ _CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, 0));
// Disable confusing "helpful" text message on abort, Ctrl-C
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
#endif
@@ -826,35 +857,30 @@ bool AppInitBasicSetup()
#endif
typedef BOOL (WINAPI *PSETPROCDEPPOL)(DWORD);
PSETPROCDEPPOL setProcDEPPol = (PSETPROCDEPPOL)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "SetProcessDEPPolicy");
- if (setProcDEPPol != NULL) setProcDEPPol(PROCESS_DEP_ENABLE);
+ if (setProcDEPPol != nullptr) setProcDEPPol(PROCESS_DEP_ENABLE);
#endif
if (!SetupNetworking())
return InitError("Initializing networking failed");
#ifndef WIN32
- if (!GetBoolArg("-sysperms", false)) {
+ if (!gArgs.GetBoolArg("-sysperms", false)) {
umask(077);
}
// Clean shutdown on SIGTERM
- struct sigaction sa;
- sa.sa_handler = HandleSIGTERM;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = 0;
- sigaction(SIGTERM, &sa, NULL);
- sigaction(SIGINT, &sa, NULL);
+ registerSignalHandler(SIGTERM, HandleSIGTERM);
+ registerSignalHandler(SIGINT, HandleSIGTERM);
// Reopen debug.log on SIGHUP
- struct sigaction sa_hup;
- sa_hup.sa_handler = HandleSIGHUP;
- sigemptyset(&sa_hup.sa_mask);
- sa_hup.sa_flags = 0;
- sigaction(SIGHUP, &sa_hup, NULL);
+ registerSignalHandler(SIGHUP, HandleSIGHUP);
// Ignore SIGPIPE, otherwise it will bring the daemon down if the client closes unexpectedly
signal(SIGPIPE, SIG_IGN);
#endif
+
+ std::set_new_handler(new_handler_terminate);
+
return true;
}
@@ -866,16 +892,20 @@ bool AppInitParameterInteraction()
// also see: InitParameterInteraction()
// if using block pruning, then disallow txindex
- if (GetArg("-prune", 0)) {
- if (GetBoolArg("-txindex", DEFAULT_TXINDEX))
+ if (gArgs.GetArg("-prune", 0)) {
+ if (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX))
return InitError(_("Prune mode is incompatible with -txindex."));
}
+ // -bind and -whitebind can't be set when not listening
+ size_t nUserBind = gArgs.GetArgs("-bind").size() + gArgs.GetArgs("-whitebind").size();
+ if (nUserBind != 0 && !gArgs.GetBoolArg("-listen", DEFAULT_LISTEN)) {
+ return InitError("Cannot set -bind or -whitebind together with -listen=0");
+ }
+
// Make sure enough file descriptors are available
- int nBind = std::max(
- (mapMultiArgs.count("-bind") ? mapMultiArgs.at("-bind").size() : 0) +
- (mapMultiArgs.count("-whitebind") ? mapMultiArgs.at("-whitebind").size() : 0), size_t(1));
- nUserMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS);
+ int nBind = std::max(nUserBind, size_t(1));
+ nUserMaxConnections = gArgs.GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS);
nMaxConnections = std::max(nUserMaxConnections, 0);
// Trim requested connection counts, to fit into system limitations
@@ -889,65 +919,96 @@ bool AppInitParameterInteraction()
InitWarning(strprintf(_("Reducing -maxconnections from %d to %d, because of system limitations."), nUserMaxConnections, nMaxConnections));
// ********************************************************* Step 3: parameter-to-internal-flags
+ if (gArgs.IsArgSet("-debug")) {
+ // Special-case: if -debug=0/-nodebug is set, turn off debugging messages
+ const std::vector<std::string> categories = gArgs.GetArgs("-debug");
+
+ if (find(categories.begin(), categories.end(), std::string("0")) == categories.end()) {
+ for (const auto& cat : categories) {
+ uint32_t flag = 0;
+ if (!GetLogCategory(&flag, &cat)) {
+ InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debug", cat));
+ continue;
+ }
+ logCategories |= flag;
+ }
+ }
+ }
- fDebug = mapMultiArgs.count("-debug");
- // Special-case: if -debug=0/-nodebug is set, turn off debugging messages
- if (fDebug) {
- const vector<string>& categories = mapMultiArgs.at("-debug");
- if (GetBoolArg("-nodebug", false) || find(categories.begin(), categories.end(), string("0")) != categories.end())
- fDebug = false;
+ // Now remove the logging categories which were explicitly excluded
+ for (const std::string& cat : gArgs.GetArgs("-debugexclude")) {
+ uint32_t flag = 0;
+ if (!GetLogCategory(&flag, &cat)) {
+ InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debugexclude", cat));
+ continue;
+ }
+ logCategories &= ~flag;
}
// Check for -debugnet
- if (GetBoolArg("-debugnet", false))
+ if (gArgs.GetBoolArg("-debugnet", false))
InitWarning(_("Unsupported argument -debugnet ignored, use -debug=net."));
// Check for -socks - as this is a privacy risk to continue, exit here
- if (IsArgSet("-socks"))
+ if (gArgs.IsArgSet("-socks"))
return InitError(_("Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported."));
// Check for -tor - as this is a privacy risk to continue, exit here
- if (GetBoolArg("-tor", false))
+ if (gArgs.GetBoolArg("-tor", false))
return InitError(_("Unsupported argument -tor found, use -onion."));
- if (GetBoolArg("-benchmark", false))
+ if (gArgs.GetBoolArg("-benchmark", false))
InitWarning(_("Unsupported argument -benchmark ignored, use -debug=bench."));
- if (GetBoolArg("-whitelistalwaysrelay", false))
+ if (gArgs.GetBoolArg("-whitelistalwaysrelay", false))
InitWarning(_("Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay."));
- if (IsArgSet("-blockminsize"))
+ if (gArgs.IsArgSet("-blockminsize"))
InitWarning("Unsupported argument -blockminsize ignored.");
// Checkmempool and checkblockindex default to true in regtest mode
- int ratio = std::min<int>(std::max<int>(GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000);
+ int ratio = std::min<int>(std::max<int>(gArgs.GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000);
if (ratio != 0) {
mempool.setSanityCheck(1.0 / ratio);
}
- fCheckBlockIndex = GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks());
- fCheckpointsEnabled = GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED);
+ fCheckBlockIndex = gArgs.GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks());
+ fCheckpointsEnabled = gArgs.GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED);
- hashAssumeValid = uint256S(GetArg("-assumevalid", chainparams.GetConsensus().defaultAssumeValid.GetHex()));
+ hashAssumeValid = uint256S(gArgs.GetArg("-assumevalid", chainparams.GetConsensus().defaultAssumeValid.GetHex()));
if (!hashAssumeValid.IsNull())
LogPrintf("Assuming ancestors of block %s have valid signatures.\n", hashAssumeValid.GetHex());
else
LogPrintf("Validating signatures for all blocks.\n");
+ if (gArgs.IsArgSet("-minimumchainwork")) {
+ const std::string minChainWorkStr = gArgs.GetArg("-minimumchainwork", "");
+ if (!IsHexNumber(minChainWorkStr)) {
+ return InitError(strprintf("Invalid non-hex (%s) minimum chain work value specified", minChainWorkStr));
+ }
+ nMinimumChainWork = UintToArith256(uint256S(minChainWorkStr));
+ } else {
+ nMinimumChainWork = UintToArith256(chainparams.GetConsensus().nMinimumChainWork);
+ }
+ LogPrintf("Setting nMinimumChainWork=%s\n", nMinimumChainWork.GetHex());
+ if (nMinimumChainWork < UintToArith256(chainparams.GetConsensus().nMinimumChainWork)) {
+ LogPrintf("Warning: nMinimumChainWork set below default value of %s\n", chainparams.GetConsensus().nMinimumChainWork.GetHex());
+ }
+
// mempool limits
- int64_t nMempoolSizeMax = GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
- int64_t nMempoolSizeMin = GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40;
+ int64_t nMempoolSizeMax = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
+ int64_t nMempoolSizeMin = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40;
if (nMempoolSizeMax < 0 || nMempoolSizeMax < nMempoolSizeMin)
return InitError(strprintf(_("-maxmempool must be at least %d MB"), std::ceil(nMempoolSizeMin / 1000000.0)));
- // incremental relay fee sets the minimimum feerate increase necessary for BIP 125 replacement in the mempool
+ // incremental relay fee sets the minimum feerate increase necessary for BIP 125 replacement in the mempool
// and the amount the mempool min fee increases above the feerate of txs evicted due to mempool limiting.
- if (IsArgSet("-incrementalrelayfee"))
+ if (gArgs.IsArgSet("-incrementalrelayfee"))
{
CAmount n = 0;
- if (!ParseMoney(GetArg("-incrementalrelayfee", ""), n))
- return InitError(AmountErrMsg("incrementalrelayfee", GetArg("-incrementalrelayfee", "")));
+ if (!ParseMoney(gArgs.GetArg("-incrementalrelayfee", ""), n))
+ return InitError(AmountErrMsg("incrementalrelayfee", gArgs.GetArg("-incrementalrelayfee", "")));
incrementalRelayFee = CFeeRate(n);
}
// -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency
- nScriptCheckThreads = GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS);
+ nScriptCheckThreads = gArgs.GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS);
if (nScriptCheckThreads <= 0)
nScriptCheckThreads += GetNumCores();
if (nScriptCheckThreads <= 1)
@@ -956,7 +1017,7 @@ bool AppInitParameterInteraction()
nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS;
// block pruning; get the amount of disk space (in MiB) to allot for block & undo files
- int64_t nPruneArg = GetArg("-prune", 0);
+ int64_t nPruneArg = gArgs.GetArg("-prune", 0);
if (nPruneArg < 0) {
return InitError(_("Prune cannot be configured with a negative value."));
}
@@ -975,25 +1036,19 @@ bool AppInitParameterInteraction()
RegisterAllCoreRPCCommands(tableRPC);
#ifdef ENABLE_WALLET
- RegisterWalletRPCCommands(tableRPC);
+ RegisterWalletRPC(tableRPC);
#endif
- nConnectTimeout = GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT);
+ nConnectTimeout = gArgs.GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT);
if (nConnectTimeout <= 0)
nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
- // Fee-per-kilobyte amount considered the same as "free"
- // If you are mining, be careful setting this:
- // if you set it to zero then
- // a transaction spammer can cheaply fill blocks using
- // 1-satoshi-fee transactions. It should be set above the real
- // cost to you of processing a transaction.
- if (IsArgSet("-minrelaytxfee"))
- {
+ if (gArgs.IsArgSet("-minrelaytxfee")) {
CAmount n = 0;
- if (!ParseMoney(GetArg("-minrelaytxfee", ""), n) || 0 == n)
- return InitError(AmountErrMsg("minrelaytxfee", GetArg("-minrelaytxfee", "")));
- // High fee check is done afterward in CWallet::ParameterInteraction()
+ if (!ParseMoney(gArgs.GetArg("-minrelaytxfee", ""), n)) {
+ return InitError(AmountErrMsg("minrelaytxfee", gArgs.GetArg("-minrelaytxfee", "")));
+ }
+ // High fee check is done afterward in WalletParameterInteraction()
::minRelayTxFee = CFeeRate(n);
} else if (incrementalRelayFee > ::minRelayTxFee) {
// Allow only setting incrementalRelayFee to control both
@@ -1003,71 +1058,70 @@ bool AppInitParameterInteraction()
// Sanity check argument for min fee for including tx in block
// TODO: Harmonize which arguments need sanity checking and where that happens
- if (IsArgSet("-blockmintxfee"))
+ if (gArgs.IsArgSet("-blockmintxfee"))
{
CAmount n = 0;
- if (!ParseMoney(GetArg("-blockmintxfee", ""), n))
- return InitError(AmountErrMsg("blockmintxfee", GetArg("-blockmintxfee", "")));
+ if (!ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n))
+ return InitError(AmountErrMsg("blockmintxfee", gArgs.GetArg("-blockmintxfee", "")));
}
// Feerate used to define dust. Shouldn't be changed lightly as old
// implementations may inadvertently create non-standard transactions
- if (IsArgSet("-dustrelayfee"))
+ if (gArgs.IsArgSet("-dustrelayfee"))
{
CAmount n = 0;
- if (!ParseMoney(GetArg("-dustrelayfee", ""), n) || 0 == n)
- return InitError(AmountErrMsg("dustrelayfee", GetArg("-dustrelayfee", "")));
+ if (!ParseMoney(gArgs.GetArg("-dustrelayfee", ""), n) || 0 == n)
+ return InitError(AmountErrMsg("dustrelayfee", gArgs.GetArg("-dustrelayfee", "")));
dustRelayFee = CFeeRate(n);
}
- fRequireStandard = !GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard());
+ fRequireStandard = !gArgs.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard());
if (chainparams.RequireStandard() && !fRequireStandard)
return InitError(strprintf("acceptnonstdtxn is not currently supported for %s chain", chainparams.NetworkIDString()));
- nBytesPerSigOp = GetArg("-bytespersigop", nBytesPerSigOp);
+ nBytesPerSigOp = gArgs.GetArg("-bytespersigop", nBytesPerSigOp);
#ifdef ENABLE_WALLET
- if (!CWallet::ParameterInteraction())
+ if (!WalletParameterInteraction())
return false;
#endif
- fIsBareMultisigStd = GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG);
- fAcceptDatacarrier = GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER);
- nMaxDatacarrierBytes = GetArg("-datacarriersize", nMaxDatacarrierBytes);
+ fIsBareMultisigStd = gArgs.GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG);
+ fAcceptDatacarrier = gArgs.GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER);
+ nMaxDatacarrierBytes = gArgs.GetArg("-datacarriersize", nMaxDatacarrierBytes);
// Option to startup with mocktime set (used for regression testing):
- SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op
+ SetMockTime(gArgs.GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op
- if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS))
+ if (gArgs.GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS))
nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM);
- if (GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) < 0)
+ if (gArgs.GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) < 0)
return InitError("rpcserialversion must be non-negative.");
- if (GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) > 1)
+ if (gArgs.GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) > 1)
return InitError("unknown rpcserialversion requested.");
- nMaxTipAge = GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE);
+ nMaxTipAge = gArgs.GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE);
- fEnableReplacement = GetBoolArg("-mempoolreplacement", DEFAULT_ENABLE_REPLACEMENT);
- if ((!fEnableReplacement) && IsArgSet("-mempoolreplacement")) {
+ fEnableReplacement = gArgs.GetBoolArg("-mempoolreplacement", DEFAULT_ENABLE_REPLACEMENT);
+ if ((!fEnableReplacement) && gArgs.IsArgSet("-mempoolreplacement")) {
// Minimal effort at forwards compatibility
- std::string strReplacementModeList = GetArg("-mempoolreplacement", ""); // default is impossible
+ std::string strReplacementModeList = gArgs.GetArg("-mempoolreplacement", ""); // default is impossible
std::vector<std::string> vstrReplacementModes;
boost::split(vstrReplacementModes, strReplacementModeList, boost::is_any_of(","));
fEnableReplacement = (std::find(vstrReplacementModes.begin(), vstrReplacementModes.end(), "fee") != vstrReplacementModes.end());
}
- if (mapMultiArgs.count("-bip9params")) {
- // Allow overriding BIP9 parameters for testing
+ if (gArgs.IsArgSet("-vbparams")) {
+ // Allow overriding version bits parameters for testing
if (!chainparams.MineBlocksOnDemand()) {
- return InitError("BIP9 parameters may only be overridden on regtest.");
+ return InitError("Version bits parameters may only be overridden on regtest.");
}
- const vector<string>& deployments = mapMultiArgs.at("-bip9params");
- for (auto i : deployments) {
+ for (const std::string& strDeployment : gArgs.GetArgs("-vbparams")) {
std::vector<std::string> vDeploymentParams;
- boost::split(vDeploymentParams, i, boost::is_any_of(":"));
+ boost::split(vDeploymentParams, strDeployment, boost::is_any_of(":"));
if (vDeploymentParams.size() != 3) {
- return InitError("BIP9 parameters malformed, expecting deployment:start:end");
+ return InitError("Version bits parameters malformed, expecting deployment:start:end");
}
int64_t nStartTime, nTimeout;
if (!ParseInt64(vDeploymentParams[1], &nStartTime)) {
@@ -1080,9 +1134,9 @@ bool AppInitParameterInteraction()
for (int j=0; j<(int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j)
{
if (vDeploymentParams[0].compare(VersionBitsDeploymentInfo[j].name) == 0) {
- UpdateRegtestBIP9Parameters(Consensus::DeploymentPos(j), nStartTime, nTimeout);
+ UpdateVersionBitsParameters(Consensus::DeploymentPos(j), nStartTime, nTimeout);
found = true;
- LogPrintf("Setting BIP9 activation parameters for %s to start=%ld, timeout=%ld\n", vDeploymentParams[0], nStartTime, nTimeout);
+ LogPrintf("Setting version bits activation parameters for %s to start=%ld, timeout=%ld\n", vDeploymentParams[0], nStartTime, nTimeout);
break;
}
}
@@ -1099,8 +1153,8 @@ static bool LockDataDirectory(bool probeOnly)
std::string strDataDir = GetDataDir().string();
// Make sure only a single Bitcoin process is using the data directory.
- boost::filesystem::path pathLockFile = GetDataDir() / ".lock";
- FILE* file = fopen(pathLockFile.string().c_str(), "a"); // empty lock file; created if it doesn't exist.
+ fs::path pathLockFile = GetDataDir() / ".lock";
+ FILE* file = fsbridge::fopen(pathLockFile, "a"); // empty lock file; created if it doesn't exist.
if (file) fclose(file);
try {
@@ -1122,6 +1176,9 @@ bool AppInitSanityChecks()
// ********************************************************* Step 4: sanity checks
// Initialize elliptic curve code
+ std::string sha256_algo = SHA256AutoDetect();
+ LogPrintf("Using the '%s' SHA256 implementation\n", sha256_algo);
+ RandomInit();
ECC_Start();
globalVerifyHandle.reset(new ECCVerifyHandle());
@@ -1130,13 +1187,13 @@ bool AppInitSanityChecks()
return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), _(PACKAGE_NAME)));
// Probe the data directory lock to give an early error message, if possible
+ // We cannot hold the data directory lock here, as the forking for daemon() hasn't yet happened,
+ // and a fork will cause weird behavior to it.
return LockDataDirectory(true);
}
-bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
+bool AppInitLockDataDirectory()
{
- const CChainParams& chainparams = Params();
- // ********************************************************* Step 4a: application initialization
// After daemonization get the data directory lock again and hold on to it until exit
// This creates a slight window for a race condition to happen, however this condition is harmless: it
// will at most make us exit without printing a message to console.
@@ -1144,12 +1201,21 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
// Detailed error printed inside LockDataDirectory
return false;
}
+ return true;
+}
+bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
+{
+ const CChainParams& chainparams = Params();
+ // ********************************************************* Step 4a: application initialization
#ifndef WIN32
CreatePidFile(GetPidFile(), getpid());
#endif
- if (GetBoolArg("-shrinkdebugfile", !fDebug))
+ if (gArgs.GetBoolArg("-shrinkdebugfile", logCategories == BCLog::NONE)) {
+ // Do this first since it both loads a bunch of debug.log into memory,
+ // and because this needs to happen before any other debug.log printing
ShrinkDebugFile();
+ }
if (fPrintToDebugLog)
OpenDebugLog();
@@ -1158,10 +1224,11 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
LogPrintf("Startup time: %s\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()));
LogPrintf("Default data directory %s\n", GetDefaultDataDir().string());
LogPrintf("Using data directory %s\n", GetDataDir().string());
- LogPrintf("Using config file %s\n", GetConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME)).string());
+ LogPrintf("Using config file %s\n", GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)).string());
LogPrintf("Using at most %i automatic connections (%i file descriptors available)\n", nMaxConnections, nFD);
InitSignatureCache();
+ InitScriptExecutionCache();
LogPrintf("Using %u threads for script verification\n", nScriptCheckThreads);
if (nScriptCheckThreads) {
@@ -1173,12 +1240,14 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
CScheduler::Function serviceLoop = boost::bind(&CScheduler::serviceQueue, &scheduler);
threadGroup.create_thread(boost::bind(&TraceThread<CScheduler::Function>, "scheduler", serviceLoop));
+ GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
+
/* 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
* be disabled when initialisation is finished.
*/
- if (GetBoolArg("-server", false))
+ if (gArgs.GetBoolArg("-server", false))
{
uiInterface.InitMessage.connect(SetRPCWarmupStatus);
if (!AppInitServers(threadGroup))
@@ -1189,7 +1258,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
// ********************************************************* Step 5: verify wallet database integrity
#ifdef ENABLE_WALLET
- if (!CWallet::Verify())
+ if (!VerifyWallets())
return false;
#endif
// ********************************************************* Step 6: network initialization
@@ -1204,17 +1273,13 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
peerLogic.reset(new PeerLogicValidation(&connman));
RegisterValidationInterface(peerLogic.get());
- RegisterNodeSignals(GetNodeSignals());
// sanitize comments per BIP-0014, format user agent and check total size
- std::vector<string> uacomments;
- if (mapMultiArgs.count("-uacomment")) {
- BOOST_FOREACH(string cmt, mapMultiArgs.at("-uacomment"))
- {
- if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT))
- return InitError(strprintf(_("User Agent comment (%s) contains unsafe characters."), cmt));
- uacomments.push_back(cmt);
- }
+ std::vector<std::string> uacomments;
+ for (const std::string& cmt : gArgs.GetArgs("-uacomment")) {
+ if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT))
+ return InitError(strprintf(_("User Agent comment (%s) contains unsafe characters."), cmt));
+ uacomments.push_back(cmt);
}
strSubVersion = FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, uacomments);
if (strSubVersion.size() > MAX_SUBVERSION_LENGTH) {
@@ -1222,9 +1287,9 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
strSubVersion.size(), MAX_SUBVERSION_LENGTH));
}
- if (mapMultiArgs.count("-onlynet")) {
+ if (gArgs.IsArgSet("-onlynet")) {
std::set<enum Network> nets;
- BOOST_FOREACH(const std::string& snet, mapMultiArgs.at("-onlynet")) {
+ for (const std::string& snet : gArgs.GetArgs("-onlynet")) {
enum Network net = ParseNetwork(snet);
if (net == NET_UNROUTABLE)
return InitError(strprintf(_("Unknown network specified in -onlynet: '%s'"), snet));
@@ -1237,26 +1302,23 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
}
}
- if (mapMultiArgs.count("-whitelist")) {
- BOOST_FOREACH(const std::string& net, mapMultiArgs.at("-whitelist")) {
- CSubNet subnet;
- LookupSubNet(net.c_str(), subnet);
- if (!subnet.IsValid())
- return InitError(strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net));
- connman.AddWhitelistedRange(subnet);
- }
- }
+ // Check for host lookup allowed before parsing any network related parameters
+ fNameLookup = gArgs.GetBoolArg("-dns", DEFAULT_NAME_LOOKUP);
- bool proxyRandomize = GetBoolArg("-proxyrandomize", DEFAULT_PROXYRANDOMIZE);
+ bool proxyRandomize = gArgs.GetBoolArg("-proxyrandomize", DEFAULT_PROXYRANDOMIZE);
// -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", "");
+ std::string proxyArg = gArgs.GetArg("-proxy", "");
SetLimited(NET_TOR);
if (proxyArg != "" && proxyArg != "0") {
- CService resolved(LookupNumeric(proxyArg.c_str(), 9050));
- proxyType addrProxy = proxyType(resolved, proxyRandomize);
+ CService proxyAddr;
+ if (!Lookup(proxyArg.c_str(), proxyAddr, 9050, fNameLookup)) {
+ return InitError(strprintf(_("Invalid -proxy address or hostname: '%s'"), proxyArg));
+ }
+
+ proxyType addrProxy = proxyType(proxyAddr, proxyRandomize);
if (!addrProxy.IsValid())
- return InitError(strprintf(_("Invalid -proxy address: '%s'"), proxyArg));
+ return InitError(strprintf(_("Invalid -proxy address or hostname: '%s'"), proxyArg));
SetProxy(NET_IPV4, addrProxy);
SetProxy(NET_IPV6, addrProxy);
@@ -1268,69 +1330,34 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
// -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", "");
+ std::string onionArg = gArgs.GetArg("-onion", "");
if (onionArg != "") {
if (onionArg == "0") { // Handle -noonion/-onion=0
SetLimited(NET_TOR); // set onions as unreachable
} else {
- CService resolved(LookupNumeric(onionArg.c_str(), 9050));
- proxyType addrOnion = proxyType(resolved, proxyRandomize);
+ CService onionProxy;
+ if (!Lookup(onionArg.c_str(), onionProxy, 9050, fNameLookup)) {
+ return InitError(strprintf(_("Invalid -onion address or hostname: '%s'"), onionArg));
+ }
+ proxyType addrOnion = proxyType(onionProxy, proxyRandomize);
if (!addrOnion.IsValid())
- return InitError(strprintf(_("Invalid -onion address: '%s'"), onionArg));
+ return InitError(strprintf(_("Invalid -onion address or hostname: '%s'"), onionArg));
SetProxy(NET_TOR, addrOnion);
SetLimited(NET_TOR, false);
}
}
// see Step 2: parameter interactions for more information about these
- fListen = GetBoolArg("-listen", DEFAULT_LISTEN);
- fDiscover = GetBoolArg("-discover", true);
- fNameLookup = GetBoolArg("-dns", DEFAULT_NAME_LOOKUP);
- fRelayTxes = !GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY);
-
- if (fListen) {
- bool fBound = false;
- if (mapMultiArgs.count("-bind")) {
- BOOST_FOREACH(const std::string& strBind, mapMultiArgs.at("-bind")) {
- CService addrBind;
- if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false))
- return InitError(ResolveErrMsg("bind", strBind));
- fBound |= Bind(connman, addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));
- }
- }
- if (mapMultiArgs.count("-whitebind")) {
- BOOST_FOREACH(const std::string& strBind, mapMultiArgs.at("-whitebind")) {
- CService addrBind;
- if (!Lookup(strBind.c_str(), addrBind, 0, false))
- return InitError(ResolveErrMsg("whitebind", strBind));
- if (addrBind.GetPort() == 0)
- return InitError(strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind));
- fBound |= Bind(connman, addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST));
- }
- }
- if (!mapMultiArgs.count("-bind") && !mapMultiArgs.count("-whitebind")) {
- struct in_addr inaddr_any;
- inaddr_any.s_addr = INADDR_ANY;
- fBound |= Bind(connman, CService(in6addr_any, GetListenPort()), BF_NONE);
- fBound |= Bind(connman, CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE);
- }
- if (!fBound)
- return InitError(_("Failed to listen on any port. Use -listen=0 if you want this."));
- }
-
- if (mapMultiArgs.count("-externalip")) {
- BOOST_FOREACH(const std::string& strAddr, mapMultiArgs.at("-externalip")) {
- CService addrLocal;
- if (Lookup(strAddr.c_str(), addrLocal, GetListenPort(), fNameLookup) && addrLocal.IsValid())
- AddLocal(addrLocal, LOCAL_MANUAL);
- else
- return InitError(ResolveErrMsg("externalip", strAddr));
- }
- }
-
- if (mapMultiArgs.count("-seednode")) {
- BOOST_FOREACH(const std::string& strDest, mapMultiArgs.at("-seednode"))
- connman.AddOneShot(strDest);
+ fListen = gArgs.GetBoolArg("-listen", DEFAULT_LISTEN);
+ fDiscover = gArgs.GetBoolArg("-discover", true);
+ fRelayTxes = !gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY);
+
+ for (const std::string& strAddr : gArgs.GetArgs("-externalip")) {
+ CService addrLocal;
+ if (Lookup(strAddr.c_str(), addrLocal, GetListenPort(), fNameLookup) && addrLocal.IsValid())
+ AddLocal(addrLocal, LOCAL_MANUAL);
+ else
+ return InitError(ResolveErrMsg("externalip", strAddr));
}
#if ENABLE_ZMQ
@@ -1343,61 +1370,34 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
uint64_t nMaxOutboundLimit = 0; //unlimited unless -maxuploadtarget is set
uint64_t nMaxOutboundTimeframe = MAX_UPLOAD_TIMEFRAME;
- if (IsArgSet("-maxuploadtarget")) {
- nMaxOutboundLimit = GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024;
+ if (gArgs.IsArgSet("-maxuploadtarget")) {
+ nMaxOutboundLimit = gArgs.GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024;
}
// ********************************************************* Step 7: load block chain
- fReindex = GetBoolArg("-reindex", false);
- bool fReindexChainState = GetBoolArg("-reindex-chainstate", false);
-
- // Upgrading to 0.8; hard-link the old blknnnn.dat files into /blocks/
- boost::filesystem::path blocksDir = GetDataDir() / "blocks";
- if (!boost::filesystem::exists(blocksDir))
- {
- boost::filesystem::create_directories(blocksDir);
- bool linked = false;
- for (unsigned int i = 1; i < 10000; i++) {
- boost::filesystem::path source = GetDataDir() / strprintf("blk%04u.dat", i);
- if (!boost::filesystem::exists(source)) break;
- boost::filesystem::path dest = blocksDir / strprintf("blk%05u.dat", i-1);
- try {
- boost::filesystem::create_hard_link(source, dest);
- LogPrintf("Hardlinked %s -> %s\n", source.string(), dest.string());
- linked = true;
- } catch (const boost::filesystem::filesystem_error& e) {
- // Note: hardlink creation failing is not a disaster, it just means
- // blocks will get re-downloaded from peers.
- LogPrintf("Error hardlinking blk%04u.dat: %s\n", i, e.what());
- break;
- }
- }
- if (linked)
- {
- fReindex = true;
- }
- }
+ fReindex = gArgs.GetBoolArg("-reindex", false);
+ bool fReindexChainState = gArgs.GetBoolArg("-reindex-chainstate", false);
// cache size calculations
- int64_t nTotalCache = (GetArg("-dbcache", nDefaultDbCache) << 20);
+ int64_t nTotalCache = (gArgs.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 greater than nMaxDbcache
int64_t nBlockTreeDBCache = nTotalCache / 8;
- nBlockTreeDBCache = std::min(nBlockTreeDBCache, (GetBoolArg("-txindex", DEFAULT_TXINDEX) ? nMaxBlockDBAndTxIndexCache : nMaxBlockDBCache) << 20);
+ nBlockTreeDBCache = std::min(nBlockTreeDBCache, (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX) ? nMaxBlockDBAndTxIndexCache : nMaxBlockDBCache) << 20);
nTotalCache -= nBlockTreeDBCache;
int64_t nCoinDBCache = std::min(nTotalCache / 2, (nTotalCache / 4) + (1 << 23)); // use 25%-50% of the remainder for disk cache
nCoinDBCache = std::min(nCoinDBCache, nMaxCoinsDBCache << 20); // cap total coins db cache
nTotalCache -= nCoinDBCache;
nCoinCacheUsage = nTotalCache; // the rest goes to in-memory cache
- int64_t nMempoolSizeMax = GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
+ int64_t nMempoolSizeMax = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
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 (plus up to %.1fMiB of unused mempool space)\n", nCoinCacheUsage * (1.0 / 1024 / 1024), nMempoolSizeMax * (1.0 / 1024 / 1024));
bool fLoaded = false;
- while (!fLoaded) {
+ while (!fLoaded && !fRequestShutdown) {
bool fReset = fReindex;
std::string strLoadError;
@@ -1412,18 +1412,22 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
delete pcoinscatcher;
delete pblocktree;
- pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex);
- pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex || fReindexChainState);
- pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);
- pcoinsTip = new CCoinsViewCache(pcoinscatcher);
+ pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReset);
- if (fReindex) {
+ if (fReset) {
pblocktree->WriteReindexing(true);
//If we're reindexing in prune mode, wipe away unusable block files and all undo data files
if (fPruneMode)
CleanupBlockRevFiles();
}
+ if (fRequestShutdown) break;
+
+ // LoadBlockIndex will load fTxIndex from the db, or set it if
+ // we're reindexing. It will also load fHavePruned if we've
+ // ever removed a block file from disk.
+ // Note that it also sets fReindex based on the disk flag!
+ // From here on out fReindex and fReset mean something different!
if (!LoadBlockIndex(chainparams)) {
strLoadError = _("Error loading block database");
break;
@@ -1434,15 +1438,9 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
if (!mapBlockIndex.empty() && mapBlockIndex.count(chainparams.GetConsensus().hashGenesisBlock) == 0)
return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?"));
- // Initialize the block index (no-op if non-empty database was already loaded)
- if (!InitBlockIndex(chainparams)) {
- strLoadError = _("Error initializing block database");
- break;
- }
-
// Check for changed -txindex state
- if (fTxIndex != GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
- strLoadError = _("You need to rebuild the database using -reindex-chainstate to change -txindex");
+ if (fTxIndex != gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
+ strLoadError = _("You need to rebuild the database using -reindex to change -txindex");
break;
}
@@ -1453,7 +1451,51 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
break;
}
- if (!fReindex && chainActive.Tip() != NULL) {
+ // At this point blocktree args are consistent with what's on disk.
+ // If we're not mid-reindex (based on disk + args), add a genesis block on disk
+ // (otherwise we use the one already on disk).
+ // This is called again in ThreadImport after the reindex completes.
+ if (!fReindex && !LoadGenesisBlock(chainparams)) {
+ strLoadError = _("Error initializing block database");
+ break;
+ }
+
+ // At this point we're either in reindex or we've loaded a useful
+ // block tree into mapBlockIndex!
+
+ pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReset || fReindexChainState);
+ pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);
+
+ // If necessary, upgrade from older database format.
+ // This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
+ if (!pcoinsdbview->Upgrade()) {
+ strLoadError = _("Error upgrading chainstate database");
+ break;
+ }
+
+ // ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
+ if (!ReplayBlocks(chainparams, pcoinsdbview)) {
+ strLoadError = _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.");
+ break;
+ }
+
+ // The on-disk coinsdb is now in a good state, create the cache
+ pcoinsTip = new CCoinsViewCache(pcoinscatcher);
+
+ bool is_coinsview_empty = fReset || fReindexChainState || pcoinsTip->GetBestBlock().IsNull();
+ if (!is_coinsview_empty) {
+ // LoadChainTip sets chainActive based on pcoinsTip's best block
+ if (!LoadChainTip(chainparams)) {
+ strLoadError = _("Error initializing block database");
+ break;
+ }
+ assert(chainActive.Tip() != nullptr);
+ }
+
+ if (!fReset) {
+ // Note that RewindBlockIndex MUST run even if we're about to -reindex-chainstate.
+ // It both disconnects blocks based on chainActive, and drops block data in
+ // mapBlockIndex based on lack of available witness data.
uiInterface.InitMessage(_("Rewinding blocks..."));
if (!RewindBlockIndex(chainparams)) {
strLoadError = _("Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain");
@@ -1461,31 +1503,33 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
}
}
- uiInterface.InitMessage(_("Verifying blocks..."));
- if (fHavePruned && GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) {
- LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks",
- MIN_BLOCKS_TO_KEEP);
- }
+ if (!is_coinsview_empty) {
+ uiInterface.InitMessage(_("Verifying blocks..."));
+ if (fHavePruned && gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) {
+ LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks",
+ MIN_BLOCKS_TO_KEEP);
+ }
- {
- LOCK(cs_main);
- CBlockIndex* tip = chainActive.Tip();
- RPCNotifyBlockChange(true, 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;
+ {
+ LOCK(cs_main);
+ CBlockIndex* tip = chainActive.Tip();
+ RPCNotifyBlockChange(true, 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(chainparams, pcoinsdbview, GetArg("-checklevel", DEFAULT_CHECKLEVEL),
- GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) {
- strLoadError = _("Corrupted block database detected");
- break;
+ if (!CVerifyDB().VerifyDB(chainparams, pcoinsdbview, gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL),
+ gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) {
+ strLoadError = _("Corrupted block database detected");
+ break;
+ }
}
} catch (const std::exception& e) {
- if (fDebug) LogPrintf("%s\n", e.what());
+ LogPrintf("%s\n", e.what());
strLoadError = _("Error opening block database");
break;
}
@@ -1493,7 +1537,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
fLoaded = true;
} while(false);
- if (!fLoaded) {
+ if (!fLoaded && !fRequestShutdown) {
// first suggest a reindex
if (!fReset) {
bool fRet = uiInterface.ThreadSafeQuestion(
@@ -1521,18 +1565,20 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
LogPrintf("Shutdown requested. Exiting.\n");
return false;
}
- LogPrintf(" block index %15dms\n", GetTimeMillis() - nStart);
+ if (fLoaded) {
+ LogPrintf(" block index %15dms\n", GetTimeMillis() - nStart);
+ }
- boost::filesystem::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME;
- CAutoFile est_filein(fopen(est_path.string().c_str(), "rb"), SER_DISK, CLIENT_VERSION);
+ fs::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME;
+ CAutoFile est_filein(fsbridge::fopen(est_path, "rb"), SER_DISK, CLIENT_VERSION);
// Allowed to fail as this file IS missing on first startup.
if (!est_filein.IsNull())
- mempool.ReadFeeEstimates(est_filein);
+ ::feeEstimator.Read(est_filein);
fFeeEstimatesInitialized = true;
// ********************************************************* Step 8: load wallet
#ifdef ENABLE_WALLET
- if (!CWallet::InitLoadWallet())
+ if (!OpenWallets())
return false;
#else
LogPrintf("No wallet support compiled in!\n");
@@ -1552,7 +1598,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
}
if (chainparams.GetConsensus().vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout != 0) {
- // Only advertize witness capabilities if they have a reasonable start time.
+ // Only advertise witness capabilities if they have a reasonable start time.
// This allows us to have the code merged without a defined softfork, by setting its
// end time to 0.
// Note that setting NODE_WITNESS is never required: the only downside from not
@@ -1570,20 +1616,18 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
// Either install a handler to notify us when genesis activates, or set fHaveGenesis directly.
// No locking, as this happens before any background thread is started.
- if (chainActive.Tip() == NULL) {
+ if (chainActive.Tip() == nullptr) {
uiInterface.NotifyBlockTip.connect(BlockNotifyGenesisWait);
} else {
fHaveGenesis = true;
}
- if (IsArgSet("-blocknotify"))
+ if (gArgs.IsArgSet("-blocknotify"))
uiInterface.NotifyBlockTip.connect(BlockNotifyCallback);
- std::vector<boost::filesystem::path> vImportFiles;
- if (mapMultiArgs.count("-loadblock"))
- {
- BOOST_FOREACH(const std::string& strFile, mapMultiArgs.at("-loadblock"))
- vImportFiles.push_back(strFile);
+ std::vector<fs::path> vImportFiles;
+ for (const std::string& strFile : gArgs.GetArgs("-loadblock")) {
+ vImportFiles.push_back(strFile);
}
threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles));
@@ -1599,18 +1643,24 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
// ********************************************************* Step 11: start node
+ int chain_active_height;
+
//// debug print
- LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size());
- LogPrintf("nBestHeight = %d\n", chainActive.Height());
- if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION))
+ {
+ LOCK(cs_main);
+ LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size());
+ chain_active_height = chainActive.Height();
+ }
+ LogPrintf("nBestHeight = %d\n", chain_active_height);
+
+ if (gArgs.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION))
StartTorControl(threadGroup, scheduler);
Discover(threadGroup);
// Map ports with UPnP
- MapPort(GetBoolArg("-upnp", DEFAULT_UPNP));
+ MapPort(gArgs.GetBoolArg("-upnp", DEFAULT_UPNP));
- std::string strNodeError;
CConnman::Options connOptions;
connOptions.nLocalServices = nLocalServices;
connOptions.nRelevantServices = nRelevantServices;
@@ -1618,16 +1668,55 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
connOptions.nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, connOptions.nMaxConnections);
connOptions.nMaxAddnode = MAX_ADDNODE_CONNECTIONS;
connOptions.nMaxFeeler = 1;
- connOptions.nBestHeight = chainActive.Height();
+ connOptions.nBestHeight = chain_active_height;
connOptions.uiInterface = &uiInterface;
- connOptions.nSendBufferMaxSize = 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER);
- connOptions.nReceiveFloodSize = 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER);
+ connOptions.m_msgproc = peerLogic.get();
+ connOptions.nSendBufferMaxSize = 1000*gArgs.GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER);
+ connOptions.nReceiveFloodSize = 1000*gArgs.GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER);
+ connOptions.m_added_nodes = gArgs.GetArgs("-addnode");
connOptions.nMaxOutboundTimeframe = nMaxOutboundTimeframe;
connOptions.nMaxOutboundLimit = nMaxOutboundLimit;
- if (!connman.Start(scheduler, strNodeError, connOptions))
- return InitError(strNodeError);
+ for (const std::string& strBind : gArgs.GetArgs("-bind")) {
+ CService addrBind;
+ if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false)) {
+ return InitError(ResolveErrMsg("bind", strBind));
+ }
+ connOptions.vBinds.push_back(addrBind);
+ }
+ for (const std::string& strBind : gArgs.GetArgs("-whitebind")) {
+ CService addrBind;
+ if (!Lookup(strBind.c_str(), addrBind, 0, false)) {
+ return InitError(ResolveErrMsg("whitebind", strBind));
+ }
+ if (addrBind.GetPort() == 0) {
+ return InitError(strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind));
+ }
+ connOptions.vWhiteBinds.push_back(addrBind);
+ }
+
+ for (const auto& net : gArgs.GetArgs("-whitelist")) {
+ CSubNet subnet;
+ LookupSubNet(net.c_str(), subnet);
+ if (!subnet.IsValid())
+ return InitError(strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net));
+ connOptions.vWhitelistedRange.push_back(subnet);
+ }
+
+ connOptions.vSeedNodes = gArgs.GetArgs("-seednode");
+
+ // Initiate outbound connections unless connect=0
+ connOptions.m_use_addrman_outgoing = !gArgs.IsArgSet("-connect");
+ if (!connOptions.m_use_addrman_outgoing) {
+ const auto connect = gArgs.GetArgs("-connect");
+ if (connect.size() != 1 || connect[0] != "0") {
+ connOptions.m_specified_outgoing = connect;
+ }
+ }
+ if (!connman.Start(scheduler, connOptions)) {
+ return false;
+ }
// ********************************************************* Step 12: finished
@@ -1635,8 +1724,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
uiInterface.InitMessage(_("Done loading"));
#ifdef ENABLE_WALLET
- if (pwalletMain)
- pwalletMain->postInitProcess(threadGroup);
+ StartWallets(scheduler);
#endif
return !fRequestShutdown;
diff --git a/src/init.h b/src/init.h
index 8222794374..a0a824738c 100644
--- a/src/init.h
+++ b/src/init.h
@@ -27,27 +27,33 @@ void InitLogging();
void InitParameterInteraction();
/** Initialize bitcoin core: Basic context setup.
- * @note This can be done before daemonization.
+ * @note This can be done before daemonization. Do not call Shutdown() if this function fails.
* @pre Parameters should be parsed and config file should be read.
*/
bool AppInitBasicSetup();
/**
* Initialization: parameter interaction.
- * @note This can be done before daemonization.
+ * @note This can be done before daemonization. Do not call Shutdown() if this function fails.
* @pre Parameters should be parsed and config file should be read, AppInitBasicSetup should have been called.
*/
bool AppInitParameterInteraction();
/**
* Initialization sanity checks: ecc init, sanity checks, dir lock.
- * @note This can be done before daemonization.
+ * @note This can be done before daemonization. Do not call Shutdown() if this function fails.
* @pre Parameters should be parsed and config file should be read, AppInitParameterInteraction should have been called.
*/
bool AppInitSanityChecks();
/**
- * Bitcoin core main initialization.
- * @note This should only be done after daemonization.
+ * Lock bitcoin core data directory.
+ * @note This should only be done after daemonization. Do not call Shutdown() if this function fails.
* @pre Parameters should be parsed and config file should be read, AppInitSanityChecks should have been called.
*/
+bool AppInitLockDataDirectory();
+/**
+ * Bitcoin core main initialization.
+ * @note This should only be done after daemonization. Call Shutdown() if this function fails.
+ * @pre Parameters should be parsed and config file should be read, AppInitLockDataDirectory should have been called.
+ */
bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler);
/** The help message mode determines what help message to show */
diff --git a/src/key.cpp b/src/key.cpp
index b4f0dc8202..315a3978c8 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -13,7 +13,7 @@
#include <secp256k1.h>
#include <secp256k1_recovery.h>
-static secp256k1_context* secp256k1_context_sign = NULL;
+static secp256k1_context* secp256k1_context_sign = nullptr;
/** These functions are taken from the libsecp256k1 distribution and are very ugly. */
static int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) {
@@ -131,14 +131,6 @@ void CKey::MakeNewKey(bool fCompressedIn) {
fCompressed = fCompressedIn;
}
-bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) {
- if (!ec_privkey_import_der(secp256k1_context_sign, (unsigned char*)begin(), &privkey[0], privkey.size()))
- return false;
- fCompressed = fCompressedIn;
- fValid = true;
- return true;
-}
-
CPrivKey CKey::GetPrivKey() const {
assert(fValid);
CPrivKey privkey;
@@ -146,7 +138,7 @@ CPrivKey CKey::GetPrivKey() const {
size_t privkeylen;
privkey.resize(279);
privkeylen = 279;
- ret = ec_privkey_export_der(secp256k1_context_sign, (unsigned char*)&privkey[0], &privkeylen, begin(), fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
+ ret = ec_privkey_export_der(secp256k1_context_sign, (unsigned char*) privkey.data(), &privkeylen, begin(), fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
assert(ret);
privkey.resize(privkeylen);
return privkey;
@@ -173,9 +165,9 @@ bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, uint32_
unsigned char extra_entropy[32] = {0};
WriteLE32(extra_entropy, test_case);
secp256k1_ecdsa_signature sig;
- int ret = secp256k1_ecdsa_sign(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, test_case ? extra_entropy : NULL);
+ int ret = secp256k1_ecdsa_sign(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, test_case ? extra_entropy : nullptr);
assert(ret);
- secp256k1_ecdsa_signature_serialize_der(secp256k1_context_sign, (unsigned char*)&vchSig[0], &nSigLen, &sig);
+ secp256k1_ecdsa_signature_serialize_der(secp256k1_context_sign, (unsigned char*)vchSig.data(), &nSigLen, &sig);
vchSig.resize(nSigLen);
return true;
}
@@ -200,7 +192,7 @@ bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig)
vchSig.resize(65);
int rec = -1;
secp256k1_ecdsa_recoverable_signature sig;
- int ret = secp256k1_ecdsa_sign_recoverable(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, NULL);
+ int ret = secp256k1_ecdsa_sign_recoverable(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, nullptr);
assert(ret);
secp256k1_ecdsa_recoverable_signature_serialize_compact(secp256k1_context_sign, (unsigned char*)&vchSig[1], &rec, &sig);
assert(ret);
@@ -210,7 +202,7 @@ bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig)
}
bool CKey::Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck=false) {
- if (!ec_privkey_import_der(secp256k1_context_sign, (unsigned char*)begin(), &privkey[0], privkey.size()))
+ if (!ec_privkey_import_der(secp256k1_context_sign, (unsigned char*)begin(), privkey.data(), privkey.size()))
return false;
fCompressed = vchPubKey.IsCompressed();
fValid = true;
@@ -253,8 +245,8 @@ void CExtKey::SetMaster(const unsigned char *seed, unsigned int nSeedLen) {
static const unsigned char hashkey[] = {'B','i','t','c','o','i','n',' ','s','e','e','d'};
std::vector<unsigned char, secure_allocator<unsigned char>> vout(64);
CHMAC_SHA512(hashkey, sizeof(hashkey)).Write(seed, nSeedLen).Finalize(vout.data());
- key.Set(&vout[0], &vout[32], true);
- memcpy(chaincode.begin(), &vout[32], 32);
+ key.Set(vout.data(), vout.data() + 32, true);
+ memcpy(chaincode.begin(), vout.data() + 32, 32);
nDepth = 0;
nChild = 0;
memset(vchFingerprint, 0, sizeof(vchFingerprint));
@@ -297,10 +289,10 @@ bool ECC_InitSanityCheck() {
}
void ECC_Start() {
- assert(secp256k1_context_sign == NULL);
+ assert(secp256k1_context_sign == nullptr);
secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
- assert(ctx != NULL);
+ assert(ctx != nullptr);
{
// Pass in a random blinding seed to the secp256k1 context.
@@ -315,7 +307,7 @@ void ECC_Start() {
void ECC_Stop() {
secp256k1_context *ctx = secp256k1_context_sign;
- secp256k1_context_sign = NULL;
+ secp256k1_context_sign = nullptr;
if (ctx) {
secp256k1_context_destroy(ctx);
diff --git a/src/key.h b/src/key.h
index 37c74e8732..54b5be2270 100644
--- a/src/key.h
+++ b/src/key.h
@@ -45,7 +45,7 @@ private:
//! The actual byte data
std::vector<unsigned char, secure_allocator<unsigned char> > keydata;
- //! Check whether the 32-byte array pointed to be vch is valid keydata.
+ //! Check whether the 32-byte array pointed to by vch is valid keydata.
bool static Check(const unsigned char* vch);
public:
@@ -56,11 +56,6 @@ public:
keydata.resize(32);
}
- //! Destructor (again necessary because of memlocking).
- ~CKey()
- {
- }
-
friend bool operator==(const CKey& a, const CKey& b)
{
return a.fCompressed == b.fCompressed &&
@@ -94,9 +89,6 @@ public:
//! Check whether the public key corresponding to this private key is (to be) compressed.
bool IsCompressed() const { return fCompressed; }
- //! Initialize from a CPrivKey (serialized OpenSSL private key data).
- bool SetPrivKey(const CPrivKey& vchPrivKey, bool fCompressed);
-
//! Generate a new private key using a cryptographic PRNG.
void MakeNewKey(bool fCompressed);
@@ -175,6 +167,8 @@ struct CExtKey {
{
unsigned int len = ::ReadCompactSize(s);
unsigned char code[BIP32_EXTKEY_SIZE];
+ if (len != BIP32_EXTKEY_SIZE)
+ throw std::runtime_error("Invalid extended key size\n");
s.read((char *)&code[0], len);
Decode(code);
}
diff --git a/src/keystore.cpp b/src/keystore.cpp
index b17567e99b..8454175ca8 100644
--- a/src/keystore.cpp
+++ b/src/keystore.cpp
@@ -9,8 +9,6 @@
#include "pubkey.h"
#include "util.h"
-#include <boost/foreach.hpp>
-
bool CKeyStore::AddKey(const CKey &key) {
return AddKeyPubKey(key, key.GetPubKey());
}
diff --git a/src/keystore.h b/src/keystore.h
index d9290722e1..9b85ddb0ec 100644
--- a/src/keystore.h
+++ b/src/keystore.h
@@ -13,7 +13,6 @@
#include "sync.h"
#include <boost/signals2/signal.hpp>
-#include <boost/variant.hpp>
/** A virtual base class for key stores */
class CKeyStore
@@ -31,7 +30,7 @@ public:
//! Check whether a key corresponding to a given address is present in the store.
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 std::set<CKeyID> GetKeys() const =0;
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
@@ -61,9 +60,9 @@ protected:
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 AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override;
+ bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;
+ bool HaveKey(const CKeyID &address) const override
{
bool result;
{
@@ -72,20 +71,16 @@ public:
}
return result;
}
- void GetKeys(std::set<CKeyID> &setAddress) const
+ std::set<CKeyID> GetKeys() const override
{
- setAddress.clear();
- {
- LOCK(cs_KeyStore);
- KeyMap::const_iterator mi = mapKeys.begin();
- while (mi != mapKeys.end())
- {
- setAddress.insert((*mi).first);
- mi++;
- }
+ LOCK(cs_KeyStore);
+ std::set<CKeyID> set_address;
+ for (const auto& mi : mapKeys) {
+ set_address.insert(mi.first);
}
+ return set_address;
}
- bool GetKey(const CKeyID &address, CKey &keyOut) const
+ bool GetKey(const CKeyID &address, CKey &keyOut) const override
{
{
LOCK(cs_KeyStore);
@@ -98,14 +93,14 @@ public:
}
return false;
}
- virtual bool AddCScript(const CScript& redeemScript);
- virtual bool HaveCScript(const CScriptID &hash) const;
- virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const;
+ bool AddCScript(const CScript& redeemScript) override;
+ bool HaveCScript(const CScriptID &hash) const override;
+ bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const override;
- virtual bool AddWatchOnly(const CScript &dest);
- virtual bool RemoveWatchOnly(const CScript &dest);
- virtual bool HaveWatchOnly(const CScript &dest) const;
- virtual bool HaveWatchOnly() const;
+ bool AddWatchOnly(const CScript &dest) override;
+ bool RemoveWatchOnly(const CScript &dest) override;
+ bool HaveWatchOnly(const CScript &dest) const override;
+ bool HaveWatchOnly() const override;
};
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;
diff --git a/src/leveldb/Makefile b/src/leveldb/Makefile
index 07a5a1ead6..f7cc7d736c 100644
--- a/src/leveldb/Makefile
+++ b/src/leveldb/Makefile
@@ -44,6 +44,7 @@ TESTS = \
util/cache_test \
util/coding_test \
util/crc32c_test \
+ util/env_posix_test \
util/env_test \
util/hash_test
@@ -121,7 +122,7 @@ SHARED_MEMENVLIB = $(SHARED_OUTDIR)/libmemenv.a
else
# Update db.h if you change these.
SHARED_VERSION_MAJOR = 1
-SHARED_VERSION_MINOR = 19
+SHARED_VERSION_MINOR = 20
SHARED_LIB1 = libleveldb.$(PLATFORM_SHARED_EXT)
SHARED_LIB2 = $(SHARED_LIB1).$(SHARED_VERSION_MAJOR)
SHARED_LIB3 = $(SHARED_LIB1).$(SHARED_VERSION_MAJOR).$(SHARED_VERSION_MINOR)
@@ -337,6 +338,9 @@ $(STATIC_OUTDIR)/db_test:db/db_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
$(STATIC_OUTDIR)/dbformat_test:db/dbformat_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
$(CXX) $(LDFLAGS) $(CXXFLAGS) db/dbformat_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+$(STATIC_OUTDIR)/env_posix_test:util/env_posix_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
+ $(CXX) $(LDFLAGS) $(CXXFLAGS) util/env_posix_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
+
$(STATIC_OUTDIR)/env_test:util/env_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS)
$(CXX) $(LDFLAGS) $(CXXFLAGS) util/env_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
@@ -412,3 +416,9 @@ $(SHARED_OUTDIR)/%.o: %.cc
$(SHARED_OUTDIR)/%.o: %.c
$(CC) $(CFLAGS) $(PLATFORM_SHARED_CFLAGS) -c $< -o $@
+
+$(STATIC_OUTDIR)/port/port_posix_sse.o: port/port_posix_sse.cc
+ $(CXX) $(CXXFLAGS) $(PLATFORM_SSEFLAGS) -c $< -o $@
+
+$(SHARED_OUTDIR)/port/port_posix_sse.o: port/port_posix_sse.cc
+ $(CXX) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) $(PLATFORM_SSEFLAGS) -c $< -o $@
diff --git a/src/leveldb/README.md b/src/leveldb/README.md
index c75b185e0e..a010c50858 100644
--- a/src/leveldb/README.md
+++ b/src/leveldb/README.md
@@ -16,7 +16,7 @@ Authors: Sanjay Ghemawat (sanjay@google.com) and Jeff Dean (jeff@google.com)
* External activity (file system operations etc.) is relayed through a virtual interface so users can customize the operating system interactions.
# Documentation
- [LevelDB library documentation](https://rawgit.com/google/leveldb/master/doc/index.html) is online and bundled with the source code.
+ [LevelDB library documentation](https://github.com/google/leveldb/blob/master/doc/index.md) is online and bundled with the source code.
# Limitations
@@ -113,29 +113,30 @@ by the one or two disk seeks needed to fetch the data from disk.
Write performance will be mostly unaffected by whether or not the
working set fits in memory.
- readrandom : 16.677 micros/op; (approximately 60,000 reads per second)
- readseq : 0.476 micros/op; 232.3 MB/s
- readreverse : 0.724 micros/op; 152.9 MB/s
+ readrandom : 16.677 micros/op; (approximately 60,000 reads per second)
+ readseq : 0.476 micros/op; 232.3 MB/s
+ readreverse : 0.724 micros/op; 152.9 MB/s
LevelDB compacts its underlying storage data in the background to
improve read performance. The results listed above were done
immediately after a lot of random writes. The results after
compactions (which are usually triggered automatically) are better.
- readrandom : 11.602 micros/op; (approximately 85,000 reads per second)
- readseq : 0.423 micros/op; 261.8 MB/s
- readreverse : 0.663 micros/op; 166.9 MB/s
+ readrandom : 11.602 micros/op; (approximately 85,000 reads per second)
+ readseq : 0.423 micros/op; 261.8 MB/s
+ readreverse : 0.663 micros/op; 166.9 MB/s
Some of the high cost of reads comes from repeated decompression of blocks
read from disk. If we supply enough cache to the leveldb so it can hold the
uncompressed blocks in memory, the read performance improves again:
- readrandom : 9.775 micros/op; (approximately 100,000 reads per second before compaction)
- readrandom : 5.215 micros/op; (approximately 190,000 reads per second after compaction)
+ readrandom : 9.775 micros/op; (approximately 100,000 reads per second before compaction)
+ readrandom : 5.215 micros/op; (approximately 190,000 reads per second after compaction)
## Repository contents
-See doc/index.html for more explanation. See doc/impl.html for a brief overview of the implementation.
+See [doc/index.md](doc/index.md) for more explanation. See
+[doc/impl.md](doc/impl.md) for a brief overview of the implementation.
The public interface is in include/*.h. Callers should not include or
rely on the details of any other header files in this package. Those
@@ -148,7 +149,7 @@ Guide to header files:
* **include/options.h**: Control over the behavior of an entire database,
and also control over the behavior of individual reads and writes.
-* **include/comparator.h**: Abstraction for user-specified comparison function.
+* **include/comparator.h**: Abstraction for user-specified comparison function.
If you want just bytewise comparison of keys, you can use the default
comparator, but clients can write their own comparator implementations if they
want custom ordering (e.g. to handle different character encodings, etc.)
@@ -165,7 +166,7 @@ length into some other byte array.
* **include/status.h**: Status is returned from many of the public interfaces
and is used to report success and various kinds of errors.
-* **include/env.h**:
+* **include/env.h**:
Abstraction of the OS environment. A posix implementation of this interface is
in util/env_posix.cc
diff --git a/src/leveldb/build_detect_platform b/src/leveldb/build_detect_platform
index d7edab1d87..4a94715900 100755
--- a/src/leveldb/build_detect_platform
+++ b/src/leveldb/build_detect_platform
@@ -63,6 +63,7 @@ PLATFORM_SHARED_EXT="so"
PLATFORM_SHARED_LDFLAGS="-shared -Wl,-soname -Wl,"
PLATFORM_SHARED_CFLAGS="-fPIC"
PLATFORM_SHARED_VERSIONED=true
+PLATFORM_SSEFLAGS=
MEMCMP_FLAG=
if [ "$CXX" = "g++" ]; then
@@ -77,6 +78,7 @@ case "$TARGET_OS" in
COMMON_FLAGS="$MEMCMP_FLAG -lpthread -DOS_LINUX -DCYGWIN"
PLATFORM_LDFLAGS="-lpthread"
PORT_FILE=port/port_posix.cc
+ PORT_SSE_FILE=port/port_posix_sse.cc
;;
Darwin)
PLATFORM=OS_MACOSX
@@ -85,24 +87,28 @@ case "$TARGET_OS" in
[ -z "$INSTALL_PATH" ] && INSTALL_PATH=`pwd`
PLATFORM_SHARED_LDFLAGS="-dynamiclib -install_name $INSTALL_PATH/"
PORT_FILE=port/port_posix.cc
+ PORT_SSE_FILE=port/port_posix_sse.cc
;;
Linux)
PLATFORM=OS_LINUX
COMMON_FLAGS="$MEMCMP_FLAG -pthread -DOS_LINUX"
PLATFORM_LDFLAGS="-pthread"
PORT_FILE=port/port_posix.cc
+ PORT_SSE_FILE=port/port_posix_sse.cc
;;
SunOS)
PLATFORM=OS_SOLARIS
COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_SOLARIS"
PLATFORM_LIBS="-lpthread -lrt"
PORT_FILE=port/port_posix.cc
+ PORT_SSE_FILE=port/port_posix_sse.cc
;;
FreeBSD)
PLATFORM=OS_FREEBSD
COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_FREEBSD"
PLATFORM_LIBS="-lpthread"
PORT_FILE=port/port_posix.cc
+ PORT_SSE_FILE=port/port_posix_sse.cc
;;
GNU/kFreeBSD)
PLATFORM=OS_KFREEBSD
@@ -115,24 +121,28 @@ case "$TARGET_OS" in
COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_NETBSD"
PLATFORM_LIBS="-lpthread -lgcc_s"
PORT_FILE=port/port_posix.cc
+ PORT_SSE_FILE=port/port_posix_sse.cc
;;
OpenBSD)
PLATFORM=OS_OPENBSD
COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_OPENBSD"
PLATFORM_LDFLAGS="-pthread"
PORT_FILE=port/port_posix.cc
+ PORT_SSE_FILE=port/port_posix_sse.cc
;;
DragonFly)
PLATFORM=OS_DRAGONFLYBSD
COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_DRAGONFLYBSD"
PLATFORM_LIBS="-lpthread"
PORT_FILE=port/port_posix.cc
+ PORT_SSE_FILE=port/port_posix_sse.cc
;;
OS_ANDROID_CROSSCOMPILE)
PLATFORM=OS_ANDROID
COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_ANDROID -DLEVELDB_PLATFORM_POSIX"
PLATFORM_LDFLAGS="" # All pthread features are in the Android C library
PORT_FILE=port/port_posix.cc
+ PORT_SSE_FILE=port/port_posix_sse.cc
CROSS_COMPILE=true
;;
HP-UX)
@@ -140,6 +150,7 @@ case "$TARGET_OS" in
COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_HPUX"
PLATFORM_LDFLAGS="-pthread"
PORT_FILE=port/port_posix.cc
+ PORT_SSE_FILE=port/port_posix_sse.cc
# man ld: +h internal_name
PLATFORM_SHARED_LDFLAGS="-shared -Wl,+h -Wl,"
;;
@@ -148,6 +159,7 @@ case "$TARGET_OS" in
COMMON_FLAGS="$MEMCMP_FLAG -DOS_MACOSX"
[ -z "$INSTALL_PATH" ] && INSTALL_PATH=`pwd`
PORT_FILE=port/port_posix.cc
+ PORT_SSE_FILE=port/port_posix_sse.cc
PLATFORM_SHARED_EXT=
PLATFORM_SHARED_LDFLAGS=
PLATFORM_SHARED_CFLAGS=
@@ -182,7 +194,7 @@ set +f # re-enable globbing
# The sources consist of the portable files, plus the platform-specific port
# file.
-echo "SOURCES=$PORTABLE_FILES $PORT_FILE" >> $OUTPUT
+echo "SOURCES=$PORTABLE_FILES $PORT_FILE $PORT_SSE_FILE" >> $OUTPUT
echo "MEMENV_SOURCES=helpers/memenv/memenv.cc" >> $OUTPUT
if [ "$CROSS_COMPILE" = "true" ]; then
@@ -213,6 +225,21 @@ EOF
fi
rm -f $CXXOUTPUT 2>/dev/null
+
+ # Test if gcc SSE 4.2 is supported
+ $CXX $CXXFLAGS -x c++ - -o $CXXOUTPUT -msse4.2 2>/dev/null <<EOF
+ int main() {}
+EOF
+ if [ "$?" = 0 ]; then
+ PLATFORM_SSEFLAGS="-msse4.2"
+ fi
+
+ rm -f $CXXOUTPUT 2>/dev/null
+fi
+
+# Use the SSE 4.2 CRC32C intrinsics iff runtime checks indicate compiler supports them.
+if [ -n "$PLATFORM_SSEFLAGS" ]; then
+ PLATFORM_SSEFLAGS="$PLATFORM_SSEFLAGS -DLEVELDB_PLATFORM_POSIX_SSE"
fi
PLATFORM_CCFLAGS="$PLATFORM_CCFLAGS $COMMON_FLAGS"
@@ -225,6 +252,7 @@ echo "PLATFORM_LDFLAGS=$PLATFORM_LDFLAGS" >> $OUTPUT
echo "PLATFORM_LIBS=$PLATFORM_LIBS" >> $OUTPUT
echo "PLATFORM_CCFLAGS=$PLATFORM_CCFLAGS" >> $OUTPUT
echo "PLATFORM_CXXFLAGS=$PLATFORM_CXXFLAGS" >> $OUTPUT
+echo "PLATFORM_SSEFLAGS=$PLATFORM_SSEFLAGS" >> $OUTPUT
echo "PLATFORM_SHARED_CFLAGS=$PLATFORM_SHARED_CFLAGS" >> $OUTPUT
echo "PLATFORM_SHARED_EXT=$PLATFORM_SHARED_EXT" >> $OUTPUT
echo "PLATFORM_SHARED_LDFLAGS=$PLATFORM_SHARED_LDFLAGS" >> $OUTPUT
diff --git a/src/leveldb/db/db_bench.cc b/src/leveldb/db/db_bench.cc
index 7a0f5e08cd..3ad19a512b 100644
--- a/src/leveldb/db/db_bench.cc
+++ b/src/leveldb/db/db_bench.cc
@@ -84,6 +84,14 @@ static bool FLAGS_histogram = false;
// (initialized to default value by "main")
static int FLAGS_write_buffer_size = 0;
+// Number of bytes written to each file.
+// (initialized to default value by "main")
+static int FLAGS_max_file_size = 0;
+
+// Approximate size of user data packed per block (before compression.
+// (initialized to default value by "main")
+static int FLAGS_block_size = 0;
+
// Number of bytes to use as a cache of uncompressed data.
// Negative means use default settings.
static int FLAGS_cache_size = -1;
@@ -109,6 +117,7 @@ static const char* FLAGS_db = NULL;
namespace leveldb {
namespace {
+leveldb::Env* g_env = NULL;
// Helper for quickly generating random data.
class RandomGenerator {
@@ -186,7 +195,7 @@ class Stats {
done_ = 0;
bytes_ = 0;
seconds_ = 0;
- start_ = Env::Default()->NowMicros();
+ start_ = g_env->NowMicros();
finish_ = start_;
message_.clear();
}
@@ -204,7 +213,7 @@ class Stats {
}
void Stop() {
- finish_ = Env::Default()->NowMicros();
+ finish_ = g_env->NowMicros();
seconds_ = (finish_ - start_) * 1e-6;
}
@@ -214,7 +223,7 @@ class Stats {
void FinishedSingleOp() {
if (FLAGS_histogram) {
- double now = Env::Default()->NowMicros();
+ double now = g_env->NowMicros();
double micros = now - last_op_finish_;
hist_.Add(micros);
if (micros > 20000) {
@@ -404,10 +413,10 @@ class Benchmark {
reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads),
heap_counter_(0) {
std::vector<std::string> files;
- Env::Default()->GetChildren(FLAGS_db, &files);
+ g_env->GetChildren(FLAGS_db, &files);
for (size_t i = 0; i < files.size(); i++) {
if (Slice(files[i]).starts_with("heap-")) {
- Env::Default()->DeleteFile(std::string(FLAGS_db) + "/" + files[i]);
+ g_env->DeleteFile(std::string(FLAGS_db) + "/" + files[i]);
}
}
if (!FLAGS_use_existing_db) {
@@ -589,7 +598,7 @@ class Benchmark {
arg[i].shared = &shared;
arg[i].thread = new ThreadState(i);
arg[i].thread->shared = &shared;
- Env::Default()->StartThread(ThreadBody, &arg[i]);
+ g_env->StartThread(ThreadBody, &arg[i]);
}
shared.mu.Lock();
@@ -700,9 +709,12 @@ class Benchmark {
void Open() {
assert(db_ == NULL);
Options options;
+ options.env = g_env;
options.create_if_missing = !FLAGS_use_existing_db;
options.block_cache = cache_;
options.write_buffer_size = FLAGS_write_buffer_size;
+ options.max_file_size = FLAGS_max_file_size;
+ options.block_size = FLAGS_block_size;
options.max_open_files = FLAGS_open_files;
options.filter_policy = filter_policy_;
options.reuse_logs = FLAGS_reuse_logs;
@@ -925,7 +937,7 @@ class Benchmark {
char fname[100];
snprintf(fname, sizeof(fname), "%s/heap-%04d", FLAGS_db, ++heap_counter_);
WritableFile* file;
- Status s = Env::Default()->NewWritableFile(fname, &file);
+ Status s = g_env->NewWritableFile(fname, &file);
if (!s.ok()) {
fprintf(stderr, "%s\n", s.ToString().c_str());
return;
@@ -934,7 +946,7 @@ class Benchmark {
delete file;
if (!ok) {
fprintf(stderr, "heap profiling not supported\n");
- Env::Default()->DeleteFile(fname);
+ g_env->DeleteFile(fname);
}
}
};
@@ -943,6 +955,8 @@ class Benchmark {
int main(int argc, char** argv) {
FLAGS_write_buffer_size = leveldb::Options().write_buffer_size;
+ FLAGS_max_file_size = leveldb::Options().max_file_size;
+ FLAGS_block_size = leveldb::Options().block_size;
FLAGS_open_files = leveldb::Options().max_open_files;
std::string default_db_path;
@@ -973,6 +987,10 @@ int main(int argc, char** argv) {
FLAGS_value_size = n;
} else if (sscanf(argv[i], "--write_buffer_size=%d%c", &n, &junk) == 1) {
FLAGS_write_buffer_size = n;
+ } else if (sscanf(argv[i], "--max_file_size=%d%c", &n, &junk) == 1) {
+ FLAGS_max_file_size = n;
+ } else if (sscanf(argv[i], "--block_size=%d%c", &n, &junk) == 1) {
+ FLAGS_block_size = n;
} else if (sscanf(argv[i], "--cache_size=%d%c", &n, &junk) == 1) {
FLAGS_cache_size = n;
} else if (sscanf(argv[i], "--bloom_bits=%d%c", &n, &junk) == 1) {
@@ -987,9 +1005,11 @@ int main(int argc, char** argv) {
}
}
+ leveldb::g_env = leveldb::Env::Default();
+
// Choose a location for the test database if none given with --db=<path>
if (FLAGS_db == NULL) {
- leveldb::Env::Default()->GetTestDirectory(&default_db_path);
+ leveldb::g_env->GetTestDirectory(&default_db_path);
default_db_path += "/dbbench";
FLAGS_db = default_db_path.c_str();
}
diff --git a/src/leveldb/db/db_impl.cc b/src/leveldb/db/db_impl.cc
index 60f4e66e55..f43ad76794 100644
--- a/src/leveldb/db/db_impl.cc
+++ b/src/leveldb/db/db_impl.cc
@@ -96,6 +96,7 @@ Options SanitizeOptions(const std::string& dbname,
result.filter_policy = (src.filter_policy != NULL) ? ipolicy : NULL;
ClipToRange(&result.max_open_files, 64 + kNumNonTableCacheFiles, 50000);
ClipToRange(&result.write_buffer_size, 64<<10, 1<<30);
+ ClipToRange(&result.max_file_size, 1<<20, 1<<30);
ClipToRange(&result.block_size, 1<<10, 4<<20);
if (result.info_log == NULL) {
// Open a log file in the same directory as the db
diff --git a/src/leveldb/db/log_format.h b/src/leveldb/db/log_format.h
index a8c06efe18..356e69fca2 100644
--- a/src/leveldb/db/log_format.h
+++ b/src/leveldb/db/log_format.h
@@ -3,7 +3,7 @@
// found in the LICENSE file. See the AUTHORS file for names of contributors.
//
// Log format information shared by reader and writer.
-// See ../doc/log_format.txt for more detail.
+// See ../doc/log_format.md for more detail.
#ifndef STORAGE_LEVELDB_DB_LOG_FORMAT_H_
#define STORAGE_LEVELDB_DB_LOG_FORMAT_H_
diff --git a/src/leveldb/db/memtable.cc b/src/leveldb/db/memtable.cc
index bfec0a7e7a..287afdbdcb 100644
--- a/src/leveldb/db/memtable.cc
+++ b/src/leveldb/db/memtable.cc
@@ -101,7 +101,7 @@ void MemTable::Add(SequenceNumber s, ValueType type,
p += 8;
p = EncodeVarint32(p, val_size);
memcpy(p, value.data(), val_size);
- assert((p + val_size) - buf == encoded_len);
+ assert(p + val_size == buf + encoded_len);
table_.Insert(buf);
}
diff --git a/src/leveldb/db/version_set.cc b/src/leveldb/db/version_set.cc
index a5e0f77a6a..2cb6d80ed3 100644
--- a/src/leveldb/db/version_set.cc
+++ b/src/leveldb/db/version_set.cc
@@ -20,21 +20,29 @@
namespace leveldb {
-static const int kTargetFileSize = 2 * 1048576;
+static size_t TargetFileSize(const Options* options) {
+ return options->max_file_size;
+}
// Maximum bytes of overlaps in grandparent (i.e., level+2) before we
// stop building a single file in a level->level+1 compaction.
-static const int64_t kMaxGrandParentOverlapBytes = 10 * kTargetFileSize;
+static int64_t MaxGrandParentOverlapBytes(const Options* options) {
+ return 10 * TargetFileSize(options);
+}
// Maximum number of bytes in all compacted files. We avoid expanding
// the lower level file set of a compaction if it would make the
// total compaction cover more than this many bytes.
-static const int64_t kExpandedCompactionByteSizeLimit = 25 * kTargetFileSize;
+static int64_t ExpandedCompactionByteSizeLimit(const Options* options) {
+ return 25 * TargetFileSize(options);
+}
-static double MaxBytesForLevel(int level) {
+static double MaxBytesForLevel(const Options* options, int level) {
// Note: the result for level zero is not really used since we set
// the level-0 compaction threshold based on number of files.
- double result = 10 * 1048576.0; // Result for both level-0 and level-1
+
+ // Result for both level-0 and level-1
+ double result = 10. * 1048576.0;
while (level > 1) {
result *= 10;
level--;
@@ -42,8 +50,9 @@ static double MaxBytesForLevel(int level) {
return result;
}
-static uint64_t MaxFileSizeForLevel(int level) {
- return kTargetFileSize; // We could vary per level to reduce number of files?
+static uint64_t MaxFileSizeForLevel(const Options* options, int level) {
+ // We could vary per level to reduce number of files?
+ return TargetFileSize(options);
}
static int64_t TotalFileSize(const std::vector<FileMetaData*>& files) {
@@ -508,7 +517,7 @@ int Version::PickLevelForMemTableOutput(
// Check that file does not overlap too many grandparent bytes.
GetOverlappingInputs(level + 2, &start, &limit, &overlaps);
const int64_t sum = TotalFileSize(overlaps);
- if (sum > kMaxGrandParentOverlapBytes) {
+ if (sum > MaxGrandParentOverlapBytes(vset_->options_)) {
break;
}
}
@@ -1027,7 +1036,7 @@ bool VersionSet::ReuseManifest(const std::string& dscname,
manifest_type != kDescriptorFile ||
!env_->GetFileSize(dscname, &manifest_size).ok() ||
// Make new compacted MANIFEST if old one is too big
- manifest_size >= kTargetFileSize) {
+ manifest_size >= TargetFileSize(options_)) {
return false;
}
@@ -1076,7 +1085,8 @@ void VersionSet::Finalize(Version* v) {
} else {
// Compute the ratio of current size to size limit.
const uint64_t level_bytes = TotalFileSize(v->files_[level]);
- score = static_cast<double>(level_bytes) / MaxBytesForLevel(level);
+ score =
+ static_cast<double>(level_bytes) / MaxBytesForLevel(options_, level);
}
if (score > best_score) {
@@ -1290,7 +1300,7 @@ Compaction* VersionSet::PickCompaction() {
level = current_->compaction_level_;
assert(level >= 0);
assert(level+1 < config::kNumLevels);
- c = new Compaction(level);
+ c = new Compaction(options_, level);
// Pick the first file that comes after compact_pointer_[level]
for (size_t i = 0; i < current_->files_[level].size(); i++) {
@@ -1307,7 +1317,7 @@ Compaction* VersionSet::PickCompaction() {
}
} else if (seek_compaction) {
level = current_->file_to_compact_level_;
- c = new Compaction(level);
+ c = new Compaction(options_, level);
c->inputs_[0].push_back(current_->file_to_compact_);
} else {
return NULL;
@@ -1352,7 +1362,8 @@ void VersionSet::SetupOtherInputs(Compaction* c) {
const int64_t inputs1_size = TotalFileSize(c->inputs_[1]);
const int64_t expanded0_size = TotalFileSize(expanded0);
if (expanded0.size() > c->inputs_[0].size() &&
- inputs1_size + expanded0_size < kExpandedCompactionByteSizeLimit) {
+ inputs1_size + expanded0_size <
+ ExpandedCompactionByteSizeLimit(options_)) {
InternalKey new_start, new_limit;
GetRange(expanded0, &new_start, &new_limit);
std::vector<FileMetaData*> expanded1;
@@ -1414,7 +1425,7 @@ Compaction* VersionSet::CompactRange(
// and we must not pick one file and drop another older file if the
// two files overlap.
if (level > 0) {
- const uint64_t limit = MaxFileSizeForLevel(level);
+ const uint64_t limit = MaxFileSizeForLevel(options_, level);
uint64_t total = 0;
for (size_t i = 0; i < inputs.size(); i++) {
uint64_t s = inputs[i]->file_size;
@@ -1426,7 +1437,7 @@ Compaction* VersionSet::CompactRange(
}
}
- Compaction* c = new Compaction(level);
+ Compaction* c = new Compaction(options_, level);
c->input_version_ = current_;
c->input_version_->Ref();
c->inputs_[0] = inputs;
@@ -1434,9 +1445,9 @@ Compaction* VersionSet::CompactRange(
return c;
}
-Compaction::Compaction(int level)
+Compaction::Compaction(const Options* options, int level)
: level_(level),
- max_output_file_size_(MaxFileSizeForLevel(level)),
+ max_output_file_size_(MaxFileSizeForLevel(options, level)),
input_version_(NULL),
grandparent_index_(0),
seen_key_(false),
@@ -1453,12 +1464,13 @@ Compaction::~Compaction() {
}
bool Compaction::IsTrivialMove() const {
+ const VersionSet* vset = input_version_->vset_;
// Avoid a move if there is lots of overlapping grandparent data.
// Otherwise, the move could create a parent file that will require
// a very expensive merge later on.
- return (num_input_files(0) == 1 &&
- num_input_files(1) == 0 &&
- TotalFileSize(grandparents_) <= kMaxGrandParentOverlapBytes);
+ return (num_input_files(0) == 1 && num_input_files(1) == 0 &&
+ TotalFileSize(grandparents_) <=
+ MaxGrandParentOverlapBytes(vset->options_));
}
void Compaction::AddInputDeletions(VersionEdit* edit) {
@@ -1491,8 +1503,9 @@ bool Compaction::IsBaseLevelForKey(const Slice& user_key) {
}
bool Compaction::ShouldStopBefore(const Slice& internal_key) {
+ const VersionSet* vset = input_version_->vset_;
// Scan to find earliest grandparent file that contains key.
- const InternalKeyComparator* icmp = &input_version_->vset_->icmp_;
+ const InternalKeyComparator* icmp = &vset->icmp_;
while (grandparent_index_ < grandparents_.size() &&
icmp->Compare(internal_key,
grandparents_[grandparent_index_]->largest.Encode()) > 0) {
@@ -1503,7 +1516,7 @@ bool Compaction::ShouldStopBefore(const Slice& internal_key) {
}
seen_key_ = true;
- if (overlapped_bytes_ > kMaxGrandParentOverlapBytes) {
+ if (overlapped_bytes_ > MaxGrandParentOverlapBytes(vset->options_)) {
// Too much overlap for current output; start new output
overlapped_bytes_ = 0;
return true;
diff --git a/src/leveldb/db/version_set.h b/src/leveldb/db/version_set.h
index 1dec745673..7935a965a7 100644
--- a/src/leveldb/db/version_set.h
+++ b/src/leveldb/db/version_set.h
@@ -366,7 +366,7 @@ class Compaction {
friend class Version;
friend class VersionSet;
- explicit Compaction(int level);
+ Compaction(const Options* options, int level);
int level_;
uint64_t max_output_file_size_;
@@ -376,7 +376,7 @@ class Compaction {
// Each compaction reads inputs from "level_" and "level_+1"
std::vector<FileMetaData*> inputs_[2]; // The two sets of inputs
- // State used to check for number of of overlapping grandparent files
+ // State used to check for number of overlapping grandparent files
// (parent == level_ + 1, grandparent == level_ + 2)
std::vector<FileMetaData*> grandparents_;
size_t grandparent_index_; // Index in grandparent_starts_
diff --git a/src/leveldb/doc/doc.css b/src/leveldb/doc/doc.css
deleted file mode 100644
index 700c564e43..0000000000
--- a/src/leveldb/doc/doc.css
+++ /dev/null
@@ -1,89 +0,0 @@
-body {
- margin-left: 0.5in;
- margin-right: 0.5in;
- background: white;
- color: black;
-}
-
-h1 {
- margin-left: -0.2in;
- font-size: 14pt;
-}
-h2 {
- margin-left: -0in;
- font-size: 12pt;
-}
-h3 {
- margin-left: -0in;
-}
-h4 {
- margin-left: -0in;
-}
-hr {
- margin-left: -0in;
-}
-
-/* Definition lists: definition term bold */
-dt {
- font-weight: bold;
-}
-
-address {
- text-align: center;
-}
-code,samp,var {
- color: blue;
-}
-kbd {
- color: #600000;
-}
-div.note p {
- float: right;
- width: 3in;
- margin-right: 0%;
- padding: 1px;
- border: 2px solid #6060a0;
- background-color: #fffff0;
-}
-
-ul {
- margin-top: -0em;
- margin-bottom: -0em;
-}
-
-ol {
- margin-top: -0em;
- margin-bottom: -0em;
-}
-
-UL.nobullets {
- list-style-type: none;
- list-style-image: none;
- margin-left: -1em;
-}
-
-p {
- margin: 1em 0 1em 0;
- padding: 0 0 0 0;
-}
-
-pre {
- line-height: 1.3em;
- padding: 0.4em 0 0.8em 0;
- margin: 0 0 0 0;
- border: 0 0 0 0;
- color: blue;
-}
-
-.datatable {
- margin-left: auto;
- margin-right: auto;
- margin-top: 2em;
- margin-bottom: 2em;
- border: 1px solid;
-}
-
-.datatable td,th {
- padding: 0 0.5em 0 0.5em;
- text-align: right;
-}
diff --git a/src/leveldb/doc/impl.html b/src/leveldb/doc/impl.html
deleted file mode 100644
index 6a468be095..0000000000
--- a/src/leveldb/doc/impl.html
+++ /dev/null
@@ -1,213 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<link rel="stylesheet" type="text/css" href="doc.css" />
-<title>Leveldb file layout and compactions</title>
-</head>
-
-<body>
-
-<h1>Files</h1>
-
-The implementation of leveldb is similar in spirit to the
-representation of a single
-<a href="http://research.google.com/archive/bigtable.html">
-Bigtable tablet (section 5.3)</a>.
-However the organization of the files that make up the representation
-is somewhat different and is explained below.
-
-<p>
-Each database is represented by a set of files stored in a directory.
-There are several different types of files as documented below:
-<p>
-<h2>Log files</h2>
-<p>
-A log file (*.log) stores a sequence of recent updates. Each update
-is appended to the current log file. When the log file reaches a
-pre-determined size (approximately 4MB by default), it is converted
-to a sorted table (see below) and a new log file is created for future
-updates.
-<p>
-A copy of the current log file is kept in an in-memory structure (the
-<code>memtable</code>). This copy is consulted on every read so that read
-operations reflect all logged updates.
-<p>
-<h2>Sorted tables</h2>
-<p>
-A sorted table (*.sst) stores a sequence of entries sorted by key.
-Each entry is either a value for the key, or a deletion marker for the
-key. (Deletion markers are kept around to hide obsolete values
-present in older sorted tables).
-<p>
-The set of sorted tables are organized into a sequence of levels. The
-sorted table generated from a log file is placed in a special <code>young</code>
-level (also called level-0). When the number of young files exceeds a
-certain threshold (currently four), all of the young files are merged
-together with all of the overlapping level-1 files to produce a
-sequence of new level-1 files (we create a new level-1 file for every
-2MB of data.)
-<p>
-Files in the young level may contain overlapping keys. However files
-in other levels have distinct non-overlapping key ranges. Consider
-level number L where L >= 1. When the combined size of files in
-level-L exceeds (10^L) MB (i.e., 10MB for level-1, 100MB for level-2,
-...), one file in level-L, and all of the overlapping files in
-level-(L+1) are merged to form a set of new files for level-(L+1).
-These merges have the effect of gradually migrating new updates from
-the young level to the largest level using only bulk reads and writes
-(i.e., minimizing expensive seeks).
-
-<h2>Manifest</h2>
-<p>
-A MANIFEST file lists the set of sorted tables that make up each
-level, the corresponding key ranges, and other important metadata.
-A new MANIFEST file (with a new number embedded in the file name)
-is created whenever the database is reopened. The MANIFEST file is
-formatted as a log, and changes made to the serving state (as files
-are added or removed) are appended to this log.
-<p>
-<h2>Current</h2>
-<p>
-CURRENT is a simple text file that contains the name of the latest
-MANIFEST file.
-<p>
-<h2>Info logs</h2>
-<p>
-Informational messages are printed to files named LOG and LOG.old.
-<p>
-<h2>Others</h2>
-<p>
-Other files used for miscellaneous purposes may also be present
-(LOCK, *.dbtmp).
-
-<h1>Level 0</h1>
-When the log file grows above a certain size (1MB by default):
-<ul>
-<li>Create a brand new memtable and log file and direct future updates here
-<li>In the background:
-<ul>
-<li>Write the contents of the previous memtable to an sstable
-<li>Discard the memtable
-<li>Delete the old log file and the old memtable
-<li>Add the new sstable to the young (level-0) level.
-</ul>
-</ul>
-
-<h1>Compactions</h1>
-
-<p>
-When the size of level L exceeds its limit, we compact it in a
-background thread. The compaction picks a file from level L and all
-overlapping files from the next level L+1. Note that if a level-L
-file overlaps only part of a level-(L+1) file, the entire file at
-level-(L+1) is used as an input to the compaction and will be
-discarded after the compaction. Aside: because level-0 is special
-(files in it may overlap each other), we treat compactions from
-level-0 to level-1 specially: a level-0 compaction may pick more than
-one level-0 file in case some of these files overlap each other.
-
-<p>
-A compaction merges the contents of the picked files to produce a
-sequence of level-(L+1) files. We switch to producing a new
-level-(L+1) file after the current output file has reached the target
-file size (2MB). We also switch to a new output file when the key
-range of the current output file has grown enough to overlap more than
-ten level-(L+2) files. This last rule ensures that a later compaction
-of a level-(L+1) file will not pick up too much data from level-(L+2).
-
-<p>
-The old files are discarded and the new files are added to the serving
-state.
-
-<p>
-Compactions for a particular level rotate through the key space. In
-more detail, for each level L, we remember the ending key of the last
-compaction at level L. The next compaction for level L will pick the
-first file that starts after this key (wrapping around to the
-beginning of the key space if there is no such file).
-
-<p>
-Compactions drop overwritten values. They also drop deletion markers
-if there are no higher numbered levels that contain a file whose range
-overlaps the current key.
-
-<h2>Timing</h2>
-
-Level-0 compactions will read up to four 1MB files from level-0, and
-at worst all the level-1 files (10MB). I.e., we will read 14MB and
-write 14MB.
-
-<p>
-Other than the special level-0 compactions, we will pick one 2MB file
-from level L. In the worst case, this will overlap ~ 12 files from
-level L+1 (10 because level-(L+1) is ten times the size of level-L,
-and another two at the boundaries since the file ranges at level-L
-will usually not be aligned with the file ranges at level-L+1). The
-compaction will therefore read 26MB and write 26MB. Assuming a disk
-IO rate of 100MB/s (ballpark range for modern drives), the worst
-compaction cost will be approximately 0.5 second.
-
-<p>
-If we throttle the background writing to something small, say 10% of
-the full 100MB/s speed, a compaction may take up to 5 seconds. If the
-user is writing at 10MB/s, we might build up lots of level-0 files
-(~50 to hold the 5*10MB). This may significantly increase the cost of
-reads due to the overhead of merging more files together on every
-read.
-
-<p>
-Solution 1: To reduce this problem, we might want to increase the log
-switching threshold when the number of level-0 files is large. Though
-the downside is that the larger this threshold, the more memory we will
-need to hold the corresponding memtable.
-
-<p>
-Solution 2: We might want to decrease write rate artificially when the
-number of level-0 files goes up.
-
-<p>
-Solution 3: We work on reducing the cost of very wide merges.
-Perhaps most of the level-0 files will have their blocks sitting
-uncompressed in the cache and we will only need to worry about the
-O(N) complexity in the merging iterator.
-
-<h2>Number of files</h2>
-
-Instead of always making 2MB files, we could make larger files for
-larger levels to reduce the total file count, though at the expense of
-more bursty compactions. Alternatively, we could shard the set of
-files into multiple directories.
-
-<p>
-An experiment on an <code>ext3</code> filesystem on Feb 04, 2011 shows
-the following timings to do 100K file opens in directories with
-varying number of files:
-<table class="datatable">
-<tr><th>Files in directory</th><th>Microseconds to open a file</th></tr>
-<tr><td>1000</td><td>9</td>
-<tr><td>10000</td><td>10</td>
-<tr><td>100000</td><td>16</td>
-</table>
-So maybe even the sharding is not necessary on modern filesystems?
-
-<h1>Recovery</h1>
-
-<ul>
-<li> Read CURRENT to find name of the latest committed MANIFEST
-<li> Read the named MANIFEST file
-<li> Clean up stale files
-<li> We could open all sstables here, but it is probably better to be lazy...
-<li> Convert log chunk to a new level-0 sstable
-<li> Start directing new writes to a new log file with recovered sequence#
-</ul>
-
-<h1>Garbage collection of files</h1>
-
-<code>DeleteObsoleteFiles()</code> is called at the end of every
-compaction and at the end of recovery. It finds the names of all
-files in the database. It deletes all log files that are not the
-current log file. It deletes all table files that are not referenced
-from some level and are not the output of an active compaction.
-
-</body>
-</html>
diff --git a/src/leveldb/doc/impl.md b/src/leveldb/doc/impl.md
new file mode 100644
index 0000000000..4b13f2a6ba
--- /dev/null
+++ b/src/leveldb/doc/impl.md
@@ -0,0 +1,170 @@
+## Files
+
+The implementation of leveldb is similar in spirit to the representation of a
+single [Bigtable tablet (section 5.3)](http://research.google.com/archive/bigtable.html).
+However the organization of the files that make up the representation is
+somewhat different and is explained below.
+
+Each database is represented by a set of files stored in a directory. There are
+several different types of files as documented below:
+
+### Log files
+
+A log file (*.log) stores a sequence of recent updates. Each update is appended
+to the current log file. When the log file reaches a pre-determined size
+(approximately 4MB by default), it is converted to a sorted table (see below)
+and a new log file is created for future updates.
+
+A copy of the current log file is kept in an in-memory structure (the
+`memtable`). This copy is consulted on every read so that read operations
+reflect all logged updates.
+
+## Sorted tables
+
+A sorted table (*.ldb) stores a sequence of entries sorted by key. Each entry is
+either a value for the key, or a deletion marker for the key. (Deletion markers
+are kept around to hide obsolete values present in older sorted tables).
+
+The set of sorted tables are organized into a sequence of levels. The sorted
+table generated from a log file is placed in a special **young** level (also
+called level-0). When the number of young files exceeds a certain threshold
+(currently four), all of the young files are merged together with all of the
+overlapping level-1 files to produce a sequence of new level-1 files (we create
+a new level-1 file for every 2MB of data.)
+
+Files in the young level may contain overlapping keys. However files in other
+levels have distinct non-overlapping key ranges. Consider level number L where
+L >= 1. When the combined size of files in level-L exceeds (10^L) MB (i.e., 10MB
+for level-1, 100MB for level-2, ...), one file in level-L, and all of the
+overlapping files in level-(L+1) are merged to form a set of new files for
+level-(L+1). These merges have the effect of gradually migrating new updates
+from the young level to the largest level using only bulk reads and writes
+(i.e., minimizing expensive seeks).
+
+### Manifest
+
+A MANIFEST file lists the set of sorted tables that make up each level, the
+corresponding key ranges, and other important metadata. A new MANIFEST file
+(with a new number embedded in the file name) is created whenever the database
+is reopened. The MANIFEST file is formatted as a log, and changes made to the
+serving state (as files are added or removed) are appended to this log.
+
+### Current
+
+CURRENT is a simple text file that contains the name of the latest MANIFEST
+file.
+
+### Info logs
+
+Informational messages are printed to files named LOG and LOG.old.
+
+### Others
+
+Other files used for miscellaneous purposes may also be present (LOCK, *.dbtmp).
+
+## Level 0
+
+When the log file grows above a certain size (1MB by default):
+Create a brand new memtable and log file and direct future updates here
+In the background:
+Write the contents of the previous memtable to an sstable
+Discard the memtable
+Delete the old log file and the old memtable
+Add the new sstable to the young (level-0) level.
+
+## Compactions
+
+When the size of level L exceeds its limit, we compact it in a background
+thread. The compaction picks a file from level L and all overlapping files from
+the next level L+1. Note that if a level-L file overlaps only part of a
+level-(L+1) file, the entire file at level-(L+1) is used as an input to the
+compaction and will be discarded after the compaction. Aside: because level-0
+is special (files in it may overlap each other), we treat compactions from
+level-0 to level-1 specially: a level-0 compaction may pick more than one
+level-0 file in case some of these files overlap each other.
+
+A compaction merges the contents of the picked files to produce a sequence of
+level-(L+1) files. We switch to producing a new level-(L+1) file after the
+current output file has reached the target file size (2MB). We also switch to a
+new output file when the key range of the current output file has grown enough
+to overlap more than ten level-(L+2) files. This last rule ensures that a later
+compaction of a level-(L+1) file will not pick up too much data from
+level-(L+2).
+
+The old files are discarded and the new files are added to the serving state.
+
+Compactions for a particular level rotate through the key space. In more detail,
+for each level L, we remember the ending key of the last compaction at level L.
+The next compaction for level L will pick the first file that starts after this
+key (wrapping around to the beginning of the key space if there is no such
+file).
+
+Compactions drop overwritten values. They also drop deletion markers if there
+are no higher numbered levels that contain a file whose range overlaps the
+current key.
+
+### Timing
+
+Level-0 compactions will read up to four 1MB files from level-0, and at worst
+all the level-1 files (10MB). I.e., we will read 14MB and write 14MB.
+
+Other than the special level-0 compactions, we will pick one 2MB file from level
+L. In the worst case, this will overlap ~ 12 files from level L+1 (10 because
+level-(L+1) is ten times the size of level-L, and another two at the boundaries
+since the file ranges at level-L will usually not be aligned with the file
+ranges at level-L+1). The compaction will therefore read 26MB and write 26MB.
+Assuming a disk IO rate of 100MB/s (ballpark range for modern drives), the worst
+compaction cost will be approximately 0.5 second.
+
+If we throttle the background writing to something small, say 10% of the full
+100MB/s speed, a compaction may take up to 5 seconds. If the user is writing at
+10MB/s, we might build up lots of level-0 files (~50 to hold the 5*10MB). This
+may significantly increase the cost of reads due to the overhead of merging more
+files together on every read.
+
+Solution 1: To reduce this problem, we might want to increase the log switching
+threshold when the number of level-0 files is large. Though the downside is that
+the larger this threshold, the more memory we will need to hold the
+corresponding memtable.
+
+Solution 2: We might want to decrease write rate artificially when the number of
+level-0 files goes up.
+
+Solution 3: We work on reducing the cost of very wide merges. Perhaps most of
+the level-0 files will have their blocks sitting uncompressed in the cache and
+we will only need to worry about the O(N) complexity in the merging iterator.
+
+### Number of files
+
+Instead of always making 2MB files, we could make larger files for larger levels
+to reduce the total file count, though at the expense of more bursty
+compactions. Alternatively, we could shard the set of files into multiple
+directories.
+
+An experiment on an ext3 filesystem on Feb 04, 2011 shows the following timings
+to do 100K file opens in directories with varying number of files:
+
+
+| Files in directory | Microseconds to open a file |
+|-------------------:|----------------------------:|
+| 1000 | 9 |
+| 10000 | 10 |
+| 100000 | 16 |
+
+So maybe even the sharding is not necessary on modern filesystems?
+
+## Recovery
+
+* Read CURRENT to find name of the latest committed MANIFEST
+* Read the named MANIFEST file
+* Clean up stale files
+* We could open all sstables here, but it is probably better to be lazy...
+* Convert log chunk to a new level-0 sstable
+* Start directing new writes to a new log file with recovered sequence#
+
+## Garbage collection of files
+
+`DeleteObsoleteFiles()` is called at the end of every compaction and at the end
+of recovery. It finds the names of all files in the database. It deletes all log
+files that are not the current log file. It deletes all table files that are not
+referenced from some level and are not the output of an active compaction.
diff --git a/src/leveldb/doc/index.html b/src/leveldb/doc/index.html
deleted file mode 100644
index 2155192581..0000000000
--- a/src/leveldb/doc/index.html
+++ /dev/null
@@ -1,549 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<link rel="stylesheet" type="text/css" href="doc.css" />
-<title>Leveldb</title>
-</head>
-
-<body>
-<h1>Leveldb</h1>
-<address>Jeff Dean, Sanjay Ghemawat</address>
-<p>
-The <code>leveldb</code> library provides a persistent key value store. Keys and
-values are arbitrary byte arrays. The keys are ordered within the key
-value store according to a user-specified comparator function.
-
-<p>
-<h1>Opening A Database</h1>
-<p>
-A <code>leveldb</code> database has a name which corresponds to a file system
-directory. All of the contents of database are stored in this
-directory. The following example shows how to open a database,
-creating it if necessary:
-<p>
-<pre>
- #include &lt;cassert&gt;
- #include "leveldb/db.h"
-
- leveldb::DB* db;
- leveldb::Options options;
- options.create_if_missing = true;
- leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &amp;db);
- assert(status.ok());
- ...
-</pre>
-If you want to raise an error if the database already exists, add
-the following line before the <code>leveldb::DB::Open</code> call:
-<pre>
- options.error_if_exists = true;
-</pre>
-<h1>Status</h1>
-<p>
-You may have noticed the <code>leveldb::Status</code> type above. Values of this
-type are returned by most functions in <code>leveldb</code> that may encounter an
-error. You can check if such a result is ok, and also print an
-associated error message:
-<p>
-<pre>
- leveldb::Status s = ...;
- if (!s.ok()) cerr &lt;&lt; s.ToString() &lt;&lt; endl;
-</pre>
-<h1>Closing A Database</h1>
-<p>
-When you are done with a database, just delete the database object.
-Example:
-<p>
-<pre>
- ... open the db as described above ...
- ... do something with db ...
- delete db;
-</pre>
-<h1>Reads And Writes</h1>
-<p>
-The database provides <code>Put</code>, <code>Delete</code>, and <code>Get</code> methods to
-modify/query the database. For example, the following code
-moves the value stored under key1 to key2.
-<pre>
- std::string value;
- leveldb::Status s = db-&gt;Get(leveldb::ReadOptions(), key1, &amp;value);
- if (s.ok()) s = db-&gt;Put(leveldb::WriteOptions(), key2, value);
- if (s.ok()) s = db-&gt;Delete(leveldb::WriteOptions(), key1);
-</pre>
-
-<h1>Atomic Updates</h1>
-<p>
-Note that if the process dies after the Put of key2 but before the
-delete of key1, the same value may be left stored under multiple keys.
-Such problems can be avoided by using the <code>WriteBatch</code> class to
-atomically apply a set of updates:
-<p>
-<pre>
- #include "leveldb/write_batch.h"
- ...
- std::string value;
- leveldb::Status s = db-&gt;Get(leveldb::ReadOptions(), key1, &amp;value);
- if (s.ok()) {
- leveldb::WriteBatch batch;
- batch.Delete(key1);
- batch.Put(key2, value);
- s = db-&gt;Write(leveldb::WriteOptions(), &amp;batch);
- }
-</pre>
-The <code>WriteBatch</code> holds a sequence of edits to be made to the database,
-and these edits within the batch are applied in order. Note that we
-called <code>Delete</code> before <code>Put</code> so that if <code>key1</code> is identical to <code>key2</code>,
-we do not end up erroneously dropping the value entirely.
-<p>
-Apart from its atomicity benefits, <code>WriteBatch</code> may also be used to
-speed up bulk updates by placing lots of individual mutations into the
-same batch.
-
-<h1>Synchronous Writes</h1>
-By default, each write to <code>leveldb</code> is asynchronous: it
-returns after pushing the write from the process into the operating
-system. The transfer from operating system memory to the underlying
-persistent storage happens asynchronously. The <code>sync</code> flag
-can be turned on for a particular write to make the write operation
-not return until the data being written has been pushed all the way to
-persistent storage. (On Posix systems, this is implemented by calling
-either <code>fsync(...)</code> or <code>fdatasync(...)</code> or
-<code>msync(..., MS_SYNC)</code> before the write operation returns.)
-<pre>
- leveldb::WriteOptions write_options;
- write_options.sync = true;
- db-&gt;Put(write_options, ...);
-</pre>
-Asynchronous writes are often more than a thousand times as fast as
-synchronous writes. The downside of asynchronous writes is that a
-crash of the machine may cause the last few updates to be lost. Note
-that a crash of just the writing process (i.e., not a reboot) will not
-cause any loss since even when <code>sync</code> is false, an update
-is pushed from the process memory into the operating system before it
-is considered done.
-
-<p>
-Asynchronous writes can often be used safely. For example, when
-loading a large amount of data into the database you can handle lost
-updates by restarting the bulk load after a crash. A hybrid scheme is
-also possible where every Nth write is synchronous, and in the event
-of a crash, the bulk load is restarted just after the last synchronous
-write finished by the previous run. (The synchronous write can update
-a marker that describes where to restart on a crash.)
-
-<p>
-<code>WriteBatch</code> provides an alternative to asynchronous writes.
-Multiple updates may be placed in the same <code>WriteBatch</code> and
-applied together using a synchronous write (i.e.,
-<code>write_options.sync</code> is set to true). The extra cost of
-the synchronous write will be amortized across all of the writes in
-the batch.
-
-<p>
-<h1>Concurrency</h1>
-<p>
-A database may only be opened by one process at a time.
-The <code>leveldb</code> implementation acquires a lock from the
-operating system to prevent misuse. Within a single process, the
-same <code>leveldb::DB</code> object may be safely shared by multiple
-concurrent threads. I.e., different threads may write into or fetch
-iterators or call <code>Get</code> on the same database without any
-external synchronization (the leveldb implementation will
-automatically do the required synchronization). However other objects
-(like Iterator and WriteBatch) may require external synchronization.
-If two threads share such an object, they must protect access to it
-using their own locking protocol. More details are available in
-the public header files.
-<p>
-<h1>Iteration</h1>
-<p>
-The following example demonstrates how to print all key,value pairs
-in a database.
-<p>
-<pre>
- leveldb::Iterator* it = db-&gt;NewIterator(leveldb::ReadOptions());
- for (it-&gt;SeekToFirst(); it-&gt;Valid(); it-&gt;Next()) {
- cout &lt;&lt; it-&gt;key().ToString() &lt;&lt; ": " &lt;&lt; it-&gt;value().ToString() &lt;&lt; endl;
- }
- assert(it-&gt;status().ok()); // Check for any errors found during the scan
- delete it;
-</pre>
-The following variation shows how to process just the keys in the
-range <code>[start,limit)</code>:
-<p>
-<pre>
- for (it-&gt;Seek(start);
- it-&gt;Valid() &amp;&amp; it-&gt;key().ToString() &lt; limit;
- it-&gt;Next()) {
- ...
- }
-</pre>
-You can also process entries in reverse order. (Caveat: reverse
-iteration may be somewhat slower than forward iteration.)
-<p>
-<pre>
- for (it-&gt;SeekToLast(); it-&gt;Valid(); it-&gt;Prev()) {
- ...
- }
-</pre>
-<h1>Snapshots</h1>
-<p>
-Snapshots provide consistent read-only views over the entire state of
-the key-value store. <code>ReadOptions::snapshot</code> may be non-NULL to indicate
-that a read should operate on a particular version of the DB state.
-If <code>ReadOptions::snapshot</code> is NULL, the read will operate on an
-implicit snapshot of the current state.
-<p>
-Snapshots are created by the DB::GetSnapshot() method:
-<p>
-<pre>
- leveldb::ReadOptions options;
- options.snapshot = db-&gt;GetSnapshot();
- ... apply some updates to db ...
- leveldb::Iterator* iter = db-&gt;NewIterator(options);
- ... read using iter to view the state when the snapshot was created ...
- delete iter;
- db-&gt;ReleaseSnapshot(options.snapshot);
-</pre>
-Note that when a snapshot is no longer needed, it should be released
-using the DB::ReleaseSnapshot interface. This allows the
-implementation to get rid of state that was being maintained just to
-support reading as of that snapshot.
-<h1>Slice</h1>
-<p>
-The return value of the <code>it->key()</code> and <code>it->value()</code> calls above
-are instances of the <code>leveldb::Slice</code> type. <code>Slice</code> is a simple
-structure that contains a length and a pointer to an external byte
-array. Returning a <code>Slice</code> is a cheaper alternative to returning a
-<code>std::string</code> since we do not need to copy potentially large keys and
-values. In addition, <code>leveldb</code> methods do not return null-terminated
-C-style strings since <code>leveldb</code> keys and values are allowed to
-contain '\0' bytes.
-<p>
-C++ strings and null-terminated C-style strings can be easily converted
-to a Slice:
-<p>
-<pre>
- leveldb::Slice s1 = "hello";
-
- std::string str("world");
- leveldb::Slice s2 = str;
-</pre>
-A Slice can be easily converted back to a C++ string:
-<pre>
- std::string str = s1.ToString();
- assert(str == std::string("hello"));
-</pre>
-Be careful when using Slices since it is up to the caller to ensure that
-the external byte array into which the Slice points remains live while
-the Slice is in use. For example, the following is buggy:
-<p>
-<pre>
- leveldb::Slice slice;
- if (...) {
- std::string str = ...;
- slice = str;
- }
- Use(slice);
-</pre>
-When the <code>if</code> statement goes out of scope, <code>str</code> will be destroyed and the
-backing storage for <code>slice</code> will disappear.
-<p>
-<h1>Comparators</h1>
-<p>
-The preceding examples used the default ordering function for key,
-which orders bytes lexicographically. You can however supply a custom
-comparator when opening a database. For example, suppose each
-database key consists of two numbers and we should sort by the first
-number, breaking ties by the second number. First, define a proper
-subclass of <code>leveldb::Comparator</code> that expresses these rules:
-<p>
-<pre>
- class TwoPartComparator : public leveldb::Comparator {
- public:
- // Three-way comparison function:
- // if a &lt; b: negative result
- // if a &gt; b: positive result
- // else: zero result
- int Compare(const leveldb::Slice&amp; a, const leveldb::Slice&amp; b) const {
- int a1, a2, b1, b2;
- ParseKey(a, &amp;a1, &amp;a2);
- ParseKey(b, &amp;b1, &amp;b2);
- if (a1 &lt; b1) return -1;
- if (a1 &gt; b1) return +1;
- if (a2 &lt; b2) return -1;
- if (a2 &gt; b2) return +1;
- return 0;
- }
-
- // Ignore the following methods for now:
- const char* Name() const { return "TwoPartComparator"; }
- void FindShortestSeparator(std::string*, const leveldb::Slice&amp;) const { }
- void FindShortSuccessor(std::string*) const { }
- };
-</pre>
-Now create a database using this custom comparator:
-<p>
-<pre>
- TwoPartComparator cmp;
- leveldb::DB* db;
- leveldb::Options options;
- options.create_if_missing = true;
- options.comparator = &amp;cmp;
- leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &amp;db);
- ...
-</pre>
-<h2>Backwards compatibility</h2>
-<p>
-The result of the comparator's <code>Name</code> method is attached to the
-database when it is created, and is checked on every subsequent
-database open. If the name changes, the <code>leveldb::DB::Open</code> call will
-fail. Therefore, change the name if and only if the new key format
-and comparison function are incompatible with existing databases, and
-it is ok to discard the contents of all existing databases.
-<p>
-You can however still gradually evolve your key format over time with
-a little bit of pre-planning. For example, you could store a version
-number at the end of each key (one byte should suffice for most uses).
-When you wish to switch to a new key format (e.g., adding an optional
-third part to the keys processed by <code>TwoPartComparator</code>),
-(a) keep the same comparator name (b) increment the version number
-for new keys (c) change the comparator function so it uses the
-version numbers found in the keys to decide how to interpret them.
-<p>
-<h1>Performance</h1>
-<p>
-Performance can be tuned by changing the default values of the
-types defined in <code>include/leveldb/options.h</code>.
-
-<p>
-<h2>Block size</h2>
-<p>
-<code>leveldb</code> groups adjacent keys together into the same block and such a
-block is the unit of transfer to and from persistent storage. The
-default block size is approximately 4096 uncompressed bytes.
-Applications that mostly do bulk scans over the contents of the
-database may wish to increase this size. Applications that do a lot
-of point reads of small values may wish to switch to a smaller block
-size if performance measurements indicate an improvement. There isn't
-much benefit in using blocks smaller than one kilobyte, or larger than
-a few megabytes. Also note that compression will be more effective
-with larger block sizes.
-<p>
-<h2>Compression</h2>
-<p>
-Each block is individually compressed before being written to
-persistent storage. Compression is on by default since the default
-compression method is very fast, and is automatically disabled for
-uncompressible data. In rare cases, applications may want to disable
-compression entirely, but should only do so if benchmarks show a
-performance improvement:
-<p>
-<pre>
- leveldb::Options options;
- options.compression = leveldb::kNoCompression;
- ... leveldb::DB::Open(options, name, ...) ....
-</pre>
-<h2>Cache</h2>
-<p>
-The contents of the database are stored in a set of files in the
-filesystem and each file stores a sequence of compressed blocks. If
-<code>options.cache</code> is non-NULL, it is used to cache frequently used
-uncompressed block contents.
-<p>
-<pre>
- #include "leveldb/cache.h"
-
- leveldb::Options options;
- options.cache = leveldb::NewLRUCache(100 * 1048576); // 100MB cache
- leveldb::DB* db;
- leveldb::DB::Open(options, name, &db);
- ... use the db ...
- delete db
- delete options.cache;
-</pre>
-Note that the cache holds uncompressed data, and therefore it should
-be sized according to application level data sizes, without any
-reduction from compression. (Caching of compressed blocks is left to
-the operating system buffer cache, or any custom <code>Env</code>
-implementation provided by the client.)
-<p>
-When performing a bulk read, the application may wish to disable
-caching so that the data processed by the bulk read does not end up
-displacing most of the cached contents. A per-iterator option can be
-used to achieve this:
-<p>
-<pre>
- leveldb::ReadOptions options;
- options.fill_cache = false;
- leveldb::Iterator* it = db-&gt;NewIterator(options);
- for (it-&gt;SeekToFirst(); it-&gt;Valid(); it-&gt;Next()) {
- ...
- }
-</pre>
-<h2>Key Layout</h2>
-<p>
-Note that the unit of disk transfer and caching is a block. Adjacent
-keys (according to the database sort order) will usually be placed in
-the same block. Therefore the application can improve its performance
-by placing keys that are accessed together near each other and placing
-infrequently used keys in a separate region of the key space.
-<p>
-For example, suppose we are implementing a simple file system on top
-of <code>leveldb</code>. The types of entries we might wish to store are:
-<p>
-<pre>
- filename -&gt; permission-bits, length, list of file_block_ids
- file_block_id -&gt; data
-</pre>
-We might want to prefix <code>filename</code> keys with one letter (say '/') and the
-<code>file_block_id</code> keys with a different letter (say '0') so that scans
-over just the metadata do not force us to fetch and cache bulky file
-contents.
-<p>
-<h2>Filters</h2>
-<p>
-Because of the way <code>leveldb</code> data is organized on disk,
-a single <code>Get()</code> call may involve multiple reads from disk.
-The optional <code>FilterPolicy</code> mechanism can be used to reduce
-the number of disk reads substantially.
-<pre>
- leveldb::Options options;
- options.filter_policy = NewBloomFilterPolicy(10);
- leveldb::DB* db;
- leveldb::DB::Open(options, "/tmp/testdb", &amp;db);
- ... use the database ...
- delete db;
- delete options.filter_policy;
-</pre>
-The preceding code associates a
-<a href="http://en.wikipedia.org/wiki/Bloom_filter">Bloom filter</a>
-based filtering policy with the database. Bloom filter based
-filtering relies on keeping some number of bits of data in memory per
-key (in this case 10 bits per key since that is the argument we passed
-to NewBloomFilterPolicy). This filter will reduce the number of unnecessary
-disk reads needed for <code>Get()</code> calls by a factor of
-approximately a 100. Increasing the bits per key will lead to a
-larger reduction at the cost of more memory usage. We recommend that
-applications whose working set does not fit in memory and that do a
-lot of random reads set a filter policy.
-<p>
-If you are using a custom comparator, you should ensure that the filter
-policy you are using is compatible with your comparator. For example,
-consider a comparator that ignores trailing spaces when comparing keys.
-<code>NewBloomFilterPolicy</code> must not be used with such a comparator.
-Instead, the application should provide a custom filter policy that
-also ignores trailing spaces. For example:
-<pre>
- class CustomFilterPolicy : public leveldb::FilterPolicy {
- private:
- FilterPolicy* builtin_policy_;
- public:
- CustomFilterPolicy() : builtin_policy_(NewBloomFilterPolicy(10)) { }
- ~CustomFilterPolicy() { delete builtin_policy_; }
-
- const char* Name() const { return "IgnoreTrailingSpacesFilter"; }
-
- void CreateFilter(const Slice* keys, int n, std::string* dst) const {
- // Use builtin bloom filter code after removing trailing spaces
- std::vector&lt;Slice&gt; trimmed(n);
- for (int i = 0; i &lt; n; i++) {
- trimmed[i] = RemoveTrailingSpaces(keys[i]);
- }
- return builtin_policy_-&gt;CreateFilter(&amp;trimmed[i], n, dst);
- }
-
- bool KeyMayMatch(const Slice& key, const Slice& filter) const {
- // Use builtin bloom filter code after removing trailing spaces
- return builtin_policy_-&gt;KeyMayMatch(RemoveTrailingSpaces(key), filter);
- }
- };
-</pre>
-<p>
-Advanced applications may provide a filter policy that does not use
-a bloom filter but uses some other mechanism for summarizing a set
-of keys. See <code>leveldb/filter_policy.h</code> for detail.
-<p>
-<h1>Checksums</h1>
-<p>
-<code>leveldb</code> associates checksums with all data it stores in the file system.
-There are two separate controls provided over how aggressively these
-checksums are verified:
-<p>
-<ul>
-<li> <code>ReadOptions::verify_checksums</code> may be set to true to force
- checksum verification of all data that is read from the file system on
- behalf of a particular read. By default, no such verification is
- done.
-<p>
-<li> <code>Options::paranoid_checks</code> may be set to true before opening a
- database to make the database implementation raise an error as soon as
- it detects an internal corruption. Depending on which portion of the
- database has been corrupted, the error may be raised when the database
- is opened, or later by another database operation. By default,
- paranoid checking is off so that the database can be used even if
- parts of its persistent storage have been corrupted.
-<p>
- If a database is corrupted (perhaps it cannot be opened when
- paranoid checking is turned on), the <code>leveldb::RepairDB</code> function
- may be used to recover as much of the data as possible
-<p>
-</ul>
-<h1>Approximate Sizes</h1>
-<p>
-The <code>GetApproximateSizes</code> method can used to get the approximate
-number of bytes of file system space used by one or more key ranges.
-<p>
-<pre>
- leveldb::Range ranges[2];
- ranges[0] = leveldb::Range("a", "c");
- ranges[1] = leveldb::Range("x", "z");
- uint64_t sizes[2];
- leveldb::Status s = db-&gt;GetApproximateSizes(ranges, 2, sizes);
-</pre>
-The preceding call will set <code>sizes[0]</code> to the approximate number of
-bytes of file system space used by the key range <code>[a..c)</code> and
-<code>sizes[1]</code> to the approximate number of bytes used by the key range
-<code>[x..z)</code>.
-<p>
-<h1>Environment</h1>
-<p>
-All file operations (and other operating system calls) issued by the
-<code>leveldb</code> implementation are routed through a <code>leveldb::Env</code> object.
-Sophisticated clients may wish to provide their own <code>Env</code>
-implementation to get better control. For example, an application may
-introduce artificial delays in the file IO paths to limit the impact
-of <code>leveldb</code> on other activities in the system.
-<p>
-<pre>
- class SlowEnv : public leveldb::Env {
- .. implementation of the Env interface ...
- };
-
- SlowEnv env;
- leveldb::Options options;
- options.env = &amp;env;
- Status s = leveldb::DB::Open(options, ...);
-</pre>
-<h1>Porting</h1>
-<p>
-<code>leveldb</code> may be ported to a new platform by providing platform
-specific implementations of the types/methods/functions exported by
-<code>leveldb/port/port.h</code>. See <code>leveldb/port/port_example.h</code> for more
-details.
-<p>
-In addition, the new platform may need a new default <code>leveldb::Env</code>
-implementation. See <code>leveldb/util/env_posix.h</code> for an example.
-
-<h1>Other Information</h1>
-
-<p>
-Details about the <code>leveldb</code> implementation may be found in
-the following documents:
-<ul>
-<li> <a href="impl.html">Implementation notes</a>
-<li> <a href="table_format.txt">Format of an immutable Table file</a>
-<li> <a href="log_format.txt">Format of a log file</a>
-</ul>
-
-</body>
-</html>
diff --git a/src/leveldb/doc/index.md b/src/leveldb/doc/index.md
new file mode 100644
index 0000000000..be8569692b
--- /dev/null
+++ b/src/leveldb/doc/index.md
@@ -0,0 +1,523 @@
+leveldb
+=======
+
+_Jeff Dean, Sanjay Ghemawat_
+
+The leveldb library provides a persistent key value store. Keys and values are
+arbitrary byte arrays. The keys are ordered within the key value store
+according to a user-specified comparator function.
+
+## Opening A Database
+
+A leveldb database has a name which corresponds to a file system directory. All
+of the contents of database are stored in this directory. The following example
+shows how to open a database, creating it if necessary:
+
+```c++
+#include <cassert>
+#include "leveldb/db.h"
+
+leveldb::DB* db;
+leveldb::Options options;
+options.create_if_missing = true;
+leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db);
+assert(status.ok());
+...
+```
+
+If you want to raise an error if the database already exists, add the following
+line before the `leveldb::DB::Open` call:
+
+```c++
+options.error_if_exists = true;
+```
+
+## Status
+
+You may have noticed the `leveldb::Status` type above. Values of this type are
+returned by most functions in leveldb that may encounter an error. You can check
+if such a result is ok, and also print an associated error message:
+
+```c++
+leveldb::Status s = ...;
+if (!s.ok()) cerr << s.ToString() << endl;
+```
+
+## Closing A Database
+
+When you are done with a database, just delete the database object. Example:
+
+```c++
+... open the db as described above ...
+... do something with db ...
+delete db;
+```
+
+## Reads And Writes
+
+The database provides Put, Delete, and Get methods to modify/query the database.
+For example, the following code moves the value stored under key1 to key2.
+
+```c++
+std::string value;
+leveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value);
+if (s.ok()) s = db->Put(leveldb::WriteOptions(), key2, value);
+if (s.ok()) s = db->Delete(leveldb::WriteOptions(), key1);
+```
+
+## Atomic Updates
+
+Note that if the process dies after the Put of key2 but before the delete of
+key1, the same value may be left stored under multiple keys. Such problems can
+be avoided by using the `WriteBatch` class to atomically apply a set of updates:
+
+```c++
+#include "leveldb/write_batch.h"
+...
+std::string value;
+leveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value);
+if (s.ok()) {
+ leveldb::WriteBatch batch;
+ batch.Delete(key1);
+ batch.Put(key2, value);
+ s = db->Write(leveldb::WriteOptions(), &batch);
+}
+```
+
+The `WriteBatch` holds a sequence of edits to be made to the database, and these
+edits within the batch are applied in order. Note that we called Delete before
+Put so that if key1 is identical to key2, we do not end up erroneously dropping
+the value entirely.
+
+Apart from its atomicity benefits, `WriteBatch` may also be used to speed up
+bulk updates by placing lots of individual mutations into the same batch.
+
+## Synchronous Writes
+
+By default, each write to leveldb is asynchronous: it returns after pushing the
+write from the process into the operating system. The transfer from operating
+system memory to the underlying persistent storage happens asynchronously. The
+sync flag can be turned on for a particular write to make the write operation
+not return until the data being written has been pushed all the way to
+persistent storage. (On Posix systems, this is implemented by calling either
+`fsync(...)` or `fdatasync(...)` or `msync(..., MS_SYNC)` before the write
+operation returns.)
+
+```c++
+leveldb::WriteOptions write_options;
+write_options.sync = true;
+db->Put(write_options, ...);
+```
+
+Asynchronous writes are often more than a thousand times as fast as synchronous
+writes. The downside of asynchronous writes is that a crash of the machine may
+cause the last few updates to be lost. Note that a crash of just the writing
+process (i.e., not a reboot) will not cause any loss since even when sync is
+false, an update is pushed from the process memory into the operating system
+before it is considered done.
+
+Asynchronous writes can often be used safely. For example, when loading a large
+amount of data into the database you can handle lost updates by restarting the
+bulk load after a crash. A hybrid scheme is also possible where every Nth write
+is synchronous, and in the event of a crash, the bulk load is restarted just
+after the last synchronous write finished by the previous run. (The synchronous
+write can update a marker that describes where to restart on a crash.)
+
+`WriteBatch` provides an alternative to asynchronous writes. Multiple updates
+may be placed in the same WriteBatch and applied together using a synchronous
+write (i.e., `write_options.sync` is set to true). The extra cost of the
+synchronous write will be amortized across all of the writes in the batch.
+
+## Concurrency
+
+A database may only be opened by one process at a time. The leveldb
+implementation acquires a lock from the operating system to prevent misuse.
+Within a single process, the same `leveldb::DB` object may be safely shared by
+multiple concurrent threads. I.e., different threads may write into or fetch
+iterators or call Get on the same database without any external synchronization
+(the leveldb implementation will automatically do the required synchronization).
+However other objects (like Iterator and `WriteBatch`) may require external
+synchronization. If two threads share such an object, they must protect access
+to it using their own locking protocol. More details are available in the public
+header files.
+
+## Iteration
+
+The following example demonstrates how to print all key,value pairs in a
+database.
+
+```c++
+leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());
+for (it->SeekToFirst(); it->Valid(); it->Next()) {
+ cout << it->key().ToString() << ": " << it->value().ToString() << endl;
+}
+assert(it->status().ok()); // Check for any errors found during the scan
+delete it;
+```
+
+The following variation shows how to process just the keys in the range
+[start,limit):
+
+```c++
+for (it->Seek(start);
+ it->Valid() && it->key().ToString() < limit;
+ it->Next()) {
+ ...
+}
+```
+
+You can also process entries in reverse order. (Caveat: reverse iteration may be
+somewhat slower than forward iteration.)
+
+```c++
+for (it->SeekToLast(); it->Valid(); it->Prev()) {
+ ...
+}
+```
+
+## Snapshots
+
+Snapshots provide consistent read-only views over the entire state of the
+key-value store. `ReadOptions::snapshot` may be non-NULL to indicate that a
+read should operate on a particular version of the DB state. If
+`ReadOptions::snapshot` is NULL, the read will operate on an implicit snapshot
+of the current state.
+
+Snapshots are created by the `DB::GetSnapshot()` method:
+
+```c++
+leveldb::ReadOptions options;
+options.snapshot = db->GetSnapshot();
+... apply some updates to db ...
+leveldb::Iterator* iter = db->NewIterator(options);
+... read using iter to view the state when the snapshot was created ...
+delete iter;
+db->ReleaseSnapshot(options.snapshot);
+```
+
+Note that when a snapshot is no longer needed, it should be released using the
+`DB::ReleaseSnapshot` interface. This allows the implementation to get rid of
+state that was being maintained just to support reading as of that snapshot.
+
+## Slice
+
+The return value of the `it->key()` and `it->value()` calls above are instances
+of the `leveldb::Slice` type. Slice is a simple structure that contains a length
+and a pointer to an external byte array. Returning a Slice is a cheaper
+alternative to returning a `std::string` since we do not need to copy
+potentially large keys and values. In addition, leveldb methods do not return
+null-terminated C-style strings since leveldb keys and values are allowed to
+contain `'\0'` bytes.
+
+C++ strings and null-terminated C-style strings can be easily converted to a
+Slice:
+
+```c++
+leveldb::Slice s1 = "hello";
+
+std::string str("world");
+leveldb::Slice s2 = str;
+```
+
+A Slice can be easily converted back to a C++ string:
+
+```c++
+std::string str = s1.ToString();
+assert(str == std::string("hello"));
+```
+
+Be careful when using Slices since it is up to the caller to ensure that the
+external byte array into which the Slice points remains live while the Slice is
+in use. For example, the following is buggy:
+
+```c++
+leveldb::Slice slice;
+if (...) {
+ std::string str = ...;
+ slice = str;
+}
+Use(slice);
+```
+
+When the if statement goes out of scope, str will be destroyed and the backing
+storage for slice will disappear.
+
+## Comparators
+
+The preceding examples used the default ordering function for key, which orders
+bytes lexicographically. You can however supply a custom comparator when opening
+a database. For example, suppose each database key consists of two numbers and
+we should sort by the first number, breaking ties by the second number. First,
+define a proper subclass of `leveldb::Comparator` that expresses these rules:
+
+```c++
+class TwoPartComparator : public leveldb::Comparator {
+ public:
+ // Three-way comparison function:
+ // if a < b: negative result
+ // if a > b: positive result
+ // else: zero result
+ int Compare(const leveldb::Slice& a, const leveldb::Slice& b) const {
+ int a1, a2, b1, b2;
+ ParseKey(a, &a1, &a2);
+ ParseKey(b, &b1, &b2);
+ if (a1 < b1) return -1;
+ if (a1 > b1) return +1;
+ if (a2 < b2) return -1;
+ if (a2 > b2) return +1;
+ return 0;
+ }
+
+ // Ignore the following methods for now:
+ const char* Name() const { return "TwoPartComparator"; }
+ void FindShortestSeparator(std::string*, const leveldb::Slice&) const {}
+ void FindShortSuccessor(std::string*) const {}
+};
+```
+
+Now create a database using this custom comparator:
+
+```c++
+TwoPartComparator cmp;
+leveldb::DB* db;
+leveldb::Options options;
+options.create_if_missing = true;
+options.comparator = &cmp;
+leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db);
+...
+```
+
+### Backwards compatibility
+
+The result of the comparator's Name method is attached to the database when it
+is created, and is checked on every subsequent database open. If the name
+changes, the `leveldb::DB::Open` call will fail. Therefore, change the name if
+and only if the new key format and comparison function are incompatible with
+existing databases, and it is ok to discard the contents of all existing
+databases.
+
+You can however still gradually evolve your key format over time with a little
+bit of pre-planning. For example, you could store a version number at the end of
+each key (one byte should suffice for most uses). When you wish to switch to a
+new key format (e.g., adding an optional third part to the keys processed by
+`TwoPartComparator`), (a) keep the same comparator name (b) increment the
+version number for new keys (c) change the comparator function so it uses the
+version numbers found in the keys to decide how to interpret them.
+
+## Performance
+
+Performance can be tuned by changing the default values of the types defined in
+`include/leveldb/options.h`.
+
+### Block size
+
+leveldb groups adjacent keys together into the same block and such a block is
+the unit of transfer to and from persistent storage. The default block size is
+approximately 4096 uncompressed bytes. Applications that mostly do bulk scans
+over the contents of the database may wish to increase this size. Applications
+that do a lot of point reads of small values may wish to switch to a smaller
+block size if performance measurements indicate an improvement. There isn't much
+benefit in using blocks smaller than one kilobyte, or larger than a few
+megabytes. Also note that compression will be more effective with larger block
+sizes.
+
+### Compression
+
+Each block is individually compressed before being written to persistent
+storage. Compression is on by default since the default compression method is
+very fast, and is automatically disabled for uncompressible data. In rare cases,
+applications may want to disable compression entirely, but should only do so if
+benchmarks show a performance improvement:
+
+```c++
+leveldb::Options options;
+options.compression = leveldb::kNoCompression;
+... leveldb::DB::Open(options, name, ...) ....
+```
+
+### Cache
+
+The contents of the database are stored in a set of files in the filesystem and
+each file stores a sequence of compressed blocks. If options.cache is non-NULL,
+it is used to cache frequently used uncompressed block contents.
+
+```c++
+#include "leveldb/cache.h"
+
+leveldb::Options options;
+options.cache = leveldb::NewLRUCache(100 * 1048576); // 100MB cache
+leveldb::DB* db;
+leveldb::DB::Open(options, name, &db);
+... use the db ...
+delete db
+delete options.cache;
+```
+
+Note that the cache holds uncompressed data, and therefore it should be sized
+according to application level data sizes, without any reduction from
+compression. (Caching of compressed blocks is left to the operating system
+buffer cache, or any custom Env implementation provided by the client.)
+
+When performing a bulk read, the application may wish to disable caching so that
+the data processed by the bulk read does not end up displacing most of the
+cached contents. A per-iterator option can be used to achieve this:
+
+```c++
+leveldb::ReadOptions options;
+options.fill_cache = false;
+leveldb::Iterator* it = db->NewIterator(options);
+for (it->SeekToFirst(); it->Valid(); it->Next()) {
+ ...
+}
+```
+
+### Key Layout
+
+Note that the unit of disk transfer and caching is a block. Adjacent keys
+(according to the database sort order) will usually be placed in the same block.
+Therefore the application can improve its performance by placing keys that are
+accessed together near each other and placing infrequently used keys in a
+separate region of the key space.
+
+For example, suppose we are implementing a simple file system on top of leveldb.
+The types of entries we might wish to store are:
+
+ filename -> permission-bits, length, list of file_block_ids
+ file_block_id -> data
+
+We might want to prefix filename keys with one letter (say '/') and the
+`file_block_id` keys with a different letter (say '0') so that scans over just
+the metadata do not force us to fetch and cache bulky file contents.
+
+### Filters
+
+Because of the way leveldb data is organized on disk, a single `Get()` call may
+involve multiple reads from disk. The optional FilterPolicy mechanism can be
+used to reduce the number of disk reads substantially.
+
+```c++
+leveldb::Options options;
+options.filter_policy = NewBloomFilterPolicy(10);
+leveldb::DB* db;
+leveldb::DB::Open(options, "/tmp/testdb", &db);
+... use the database ...
+delete db;
+delete options.filter_policy;
+```
+
+The preceding code associates a Bloom filter based filtering policy with the
+database. Bloom filter based filtering relies on keeping some number of bits of
+data in memory per key (in this case 10 bits per key since that is the argument
+we passed to `NewBloomFilterPolicy`). This filter will reduce the number of
+unnecessary disk reads needed for Get() calls by a factor of approximately
+a 100. Increasing the bits per key will lead to a larger reduction at the cost
+of more memory usage. We recommend that applications whose working set does not
+fit in memory and that do a lot of random reads set a filter policy.
+
+If you are using a custom comparator, you should ensure that the filter policy
+you are using is compatible with your comparator. For example, consider a
+comparator that ignores trailing spaces when comparing keys.
+`NewBloomFilterPolicy` must not be used with such a comparator. Instead, the
+application should provide a custom filter policy that also ignores trailing
+spaces. For example:
+
+```c++
+class CustomFilterPolicy : public leveldb::FilterPolicy {
+ private:
+ FilterPolicy* builtin_policy_;
+
+ public:
+ CustomFilterPolicy() : builtin_policy_(NewBloomFilterPolicy(10)) {}
+ ~CustomFilterPolicy() { delete builtin_policy_; }
+
+ const char* Name() const { return "IgnoreTrailingSpacesFilter"; }
+
+ void CreateFilter(const Slice* keys, int n, std::string* dst) const {
+ // Use builtin bloom filter code after removing trailing spaces
+ std::vector<Slice> trimmed(n);
+ for (int i = 0; i < n; i++) {
+ trimmed[i] = RemoveTrailingSpaces(keys[i]);
+ }
+ return builtin_policy_->CreateFilter(&trimmed[i], n, dst);
+ }
+};
+```
+
+Advanced applications may provide a filter policy that does not use a bloom
+filter but uses some other mechanism for summarizing a set of keys. See
+`leveldb/filter_policy.h` for detail.
+
+## Checksums
+
+leveldb associates checksums with all data it stores in the file system. There
+are two separate controls provided over how aggressively these checksums are
+verified:
+
+`ReadOptions::verify_checksums` may be set to true to force checksum
+verification of all data that is read from the file system on behalf of a
+particular read. By default, no such verification is done.
+
+`Options::paranoid_checks` may be set to true before opening a database to make
+the database implementation raise an error as soon as it detects an internal
+corruption. Depending on which portion of the database has been corrupted, the
+error may be raised when the database is opened, or later by another database
+operation. By default, paranoid checking is off so that the database can be used
+even if parts of its persistent storage have been corrupted.
+
+If a database is corrupted (perhaps it cannot be opened when paranoid checking
+is turned on), the `leveldb::RepairDB` function may be used to recover as much
+of the data as possible
+
+## Approximate Sizes
+
+The `GetApproximateSizes` method can used to get the approximate number of bytes
+of file system space used by one or more key ranges.
+
+```c++
+leveldb::Range ranges[2];
+ranges[0] = leveldb::Range("a", "c");
+ranges[1] = leveldb::Range("x", "z");
+uint64_t sizes[2];
+leveldb::Status s = db->GetApproximateSizes(ranges, 2, sizes);
+```
+
+The preceding call will set `sizes[0]` to the approximate number of bytes of
+file system space used by the key range `[a..c)` and `sizes[1]` to the
+approximate number of bytes used by the key range `[x..z)`.
+
+## Environment
+
+All file operations (and other operating system calls) issued by the leveldb
+implementation are routed through a `leveldb::Env` object. Sophisticated clients
+may wish to provide their own Env implementation to get better control.
+For example, an application may introduce artificial delays in the file IO
+paths to limit the impact of leveldb on other activities in the system.
+
+```c++
+class SlowEnv : public leveldb::Env {
+ ... implementation of the Env interface ...
+};
+
+SlowEnv env;
+leveldb::Options options;
+options.env = &env;
+Status s = leveldb::DB::Open(options, ...);
+```
+
+## Porting
+
+leveldb may be ported to a new platform by providing platform specific
+implementations of the types/methods/functions exported by
+`leveldb/port/port.h`. See `leveldb/port/port_example.h` for more details.
+
+In addition, the new platform may need a new default `leveldb::Env`
+implementation. See `leveldb/util/env_posix.h` for an example.
+
+## Other Information
+
+Details about the leveldb implementation may be found in the following
+documents:
+
+1. [Implementation notes](impl.md)
+2. [Format of an immutable Table file](table_format.md)
+3. [Format of a log file](log_format.md)
diff --git a/src/leveldb/doc/log_format.md b/src/leveldb/doc/log_format.md
new file mode 100644
index 0000000000..f32cb5d7da
--- /dev/null
+++ b/src/leveldb/doc/log_format.md
@@ -0,0 +1,75 @@
+leveldb Log format
+==================
+The log file contents are a sequence of 32KB blocks. The only exception is that
+the tail of the file may contain a partial block.
+
+Each block consists of a sequence of records:
+
+ block := record* trailer?
+ record :=
+ checksum: uint32 // crc32c of type and data[] ; little-endian
+ length: uint16 // little-endian
+ type: uint8 // One of FULL, FIRST, MIDDLE, LAST
+ data: uint8[length]
+
+A record never starts within the last six bytes of a block (since it won't fit).
+Any leftover bytes here form the trailer, which must consist entirely of zero
+bytes and must be skipped by readers.
+
+Aside: if exactly seven bytes are left in the current block, and a new non-zero
+length record is added, the writer must emit a FIRST record (which contains zero
+bytes of user data) to fill up the trailing seven bytes of the block and then
+emit all of the user data in subsequent blocks.
+
+More types may be added in the future. Some Readers may skip record types they
+do not understand, others may report that some data was skipped.
+
+ FULL == 1
+ FIRST == 2
+ MIDDLE == 3
+ LAST == 4
+
+The FULL record contains the contents of an entire user record.
+
+FIRST, MIDDLE, LAST are types used for user records that have been split into
+multiple fragments (typically because of block boundaries). FIRST is the type
+of the first fragment of a user record, LAST is the type of the last fragment of
+a user record, and MIDDLE is the type of all interior fragments of a user
+record.
+
+Example: consider a sequence of user records:
+
+ A: length 1000
+ B: length 97270
+ C: length 8000
+
+**A** will be stored as a FULL record in the first block.
+
+**B** will be split into three fragments: first fragment occupies the rest of
+the first block, second fragment occupies the entirety of the second block, and
+the third fragment occupies a prefix of the third block. This will leave six
+bytes free in the third block, which will be left empty as the trailer.
+
+**C** will be stored as a FULL record in the fourth block.
+
+----
+
+## Some benefits over the recordio format:
+
+1. We do not need any heuristics for resyncing - just go to next block boundary
+ and scan. If there is a corruption, skip to the next block. As a
+ side-benefit, we do not get confused when part of the contents of one log
+ file are embedded as a record inside another log file.
+
+2. Splitting at approximate boundaries (e.g., for mapreduce) is simple: find the
+ next block boundary and skip records until we hit a FULL or FIRST record.
+
+3. We do not need extra buffering for large records.
+
+## Some downsides compared to recordio format:
+
+1. No packing of tiny records. This could be fixed by adding a new record type,
+ so it is a shortcoming of the current implementation, not necessarily the
+ format.
+
+2. No compression. Again, this could be fixed by adding new record types.
diff --git a/src/leveldb/doc/log_format.txt b/src/leveldb/doc/log_format.txt
deleted file mode 100644
index 4cca5ef6ea..0000000000
--- a/src/leveldb/doc/log_format.txt
+++ /dev/null
@@ -1,75 +0,0 @@
-The log file contents are a sequence of 32KB blocks. The only
-exception is that the tail of the file may contain a partial block.
-
-Each block consists of a sequence of records:
- block := record* trailer?
- record :=
- checksum: uint32 // crc32c of type and data[] ; little-endian
- length: uint16 // little-endian
- type: uint8 // One of FULL, FIRST, MIDDLE, LAST
- data: uint8[length]
-
-A record never starts within the last six bytes of a block (since it
-won't fit). Any leftover bytes here form the trailer, which must
-consist entirely of zero bytes and must be skipped by readers.
-
-Aside: if exactly seven bytes are left in the current block, and a new
-non-zero length record is added, the writer must emit a FIRST record
-(which contains zero bytes of user data) to fill up the trailing seven
-bytes of the block and then emit all of the user data in subsequent
-blocks.
-
-More types may be added in the future. Some Readers may skip record
-types they do not understand, others may report that some data was
-skipped.
-
-FULL == 1
-FIRST == 2
-MIDDLE == 3
-LAST == 4
-
-The FULL record contains the contents of an entire user record.
-
-FIRST, MIDDLE, LAST are types used for user records that have been
-split into multiple fragments (typically because of block boundaries).
-FIRST is the type of the first fragment of a user record, LAST is the
-type of the last fragment of a user record, and MIDDLE is the type of
-all interior fragments of a user record.
-
-Example: consider a sequence of user records:
- A: length 1000
- B: length 97270
- C: length 8000
-A will be stored as a FULL record in the first block.
-
-B will be split into three fragments: first fragment occupies the rest
-of the first block, second fragment occupies the entirety of the
-second block, and the third fragment occupies a prefix of the third
-block. This will leave six bytes free in the third block, which will
-be left empty as the trailer.
-
-C will be stored as a FULL record in the fourth block.
-
-===================
-
-Some benefits over the recordio format:
-
-(1) We do not need any heuristics for resyncing - just go to next
-block boundary and scan. If there is a corruption, skip to the next
-block. As a side-benefit, we do not get confused when part of the
-contents of one log file are embedded as a record inside another log
-file.
-
-(2) Splitting at approximate boundaries (e.g., for mapreduce) is
-simple: find the next block boundary and skip records until we
-hit a FULL or FIRST record.
-
-(3) We do not need extra buffering for large records.
-
-Some downsides compared to recordio format:
-
-(1) No packing of tiny records. This could be fixed by adding a new
-record type, so it is a shortcoming of the current implementation,
-not necessarily the format.
-
-(2) No compression. Again, this could be fixed by adding new record types.
diff --git a/src/leveldb/doc/table_format.md b/src/leveldb/doc/table_format.md
new file mode 100644
index 0000000000..5fe7e72411
--- /dev/null
+++ b/src/leveldb/doc/table_format.md
@@ -0,0 +1,107 @@
+leveldb File format
+===================
+
+ <beginning_of_file>
+ [data block 1]
+ [data block 2]
+ ...
+ [data block N]
+ [meta block 1]
+ ...
+ [meta block K]
+ [metaindex block]
+ [index block]
+ [Footer] (fixed size; starts at file_size - sizeof(Footer))
+ <end_of_file>
+
+The file contains internal pointers. Each such pointer is called
+a BlockHandle and contains the following information:
+
+ offset: varint64
+ size: varint64
+
+See [varints](https://developers.google.com/protocol-buffers/docs/encoding#varints)
+for an explanation of varint64 format.
+
+1. The sequence of key/value pairs in the file are stored in sorted
+order and partitioned into a sequence of data blocks. These blocks
+come one after another at the beginning of the file. Each data block
+is formatted according to the code in `block_builder.cc`, and then
+optionally compressed.
+
+2. After the data blocks we store a bunch of meta blocks. The
+supported meta block types are described below. More meta block types
+may be added in the future. Each meta block is again formatted using
+`block_builder.cc` and then optionally compressed.
+
+3. A "metaindex" block. It contains one entry for every other meta
+block where the key is the name of the meta block and the value is a
+BlockHandle pointing to that meta block.
+
+4. An "index" block. This block contains one entry per data block,
+where the key is a string >= last key in that data block and before
+the first key in the successive data block. The value is the
+BlockHandle for the data block.
+
+5. At the very end of the file is a fixed length footer that contains
+the BlockHandle of the metaindex and index blocks as well as a magic number.
+
+ metaindex_handle: char[p]; // Block handle for metaindex
+ index_handle: char[q]; // Block handle for index
+ padding: char[40-p-q];// zeroed bytes to make fixed length
+ // (40==2*BlockHandle::kMaxEncodedLength)
+ magic: fixed64; // == 0xdb4775248b80fb57 (little-endian)
+
+## "filter" Meta Block
+
+If a `FilterPolicy` was specified when the database was opened, a
+filter block is stored in each table. The "metaindex" block contains
+an entry that maps from `filter.<N>` to the BlockHandle for the filter
+block where `<N>` is the string returned by the filter policy's
+`Name()` method.
+
+The filter block stores a sequence of filters, where filter i contains
+the output of `FilterPolicy::CreateFilter()` on all keys that are stored
+in a block whose file offset falls within the range
+
+ [ i*base ... (i+1)*base-1 ]
+
+Currently, "base" is 2KB. So for example, if blocks X and Y start in
+the range `[ 0KB .. 2KB-1 ]`, all of the keys in X and Y will be
+converted to a filter by calling `FilterPolicy::CreateFilter()`, and the
+resulting filter will be stored as the first filter in the filter
+block.
+
+The filter block is formatted as follows:
+
+ [filter 0]
+ [filter 1]
+ [filter 2]
+ ...
+ [filter N-1]
+
+ [offset of filter 0] : 4 bytes
+ [offset of filter 1] : 4 bytes
+ [offset of filter 2] : 4 bytes
+ ...
+ [offset of filter N-1] : 4 bytes
+
+ [offset of beginning of offset array] : 4 bytes
+ lg(base) : 1 byte
+
+The offset array at the end of the filter block allows efficient
+mapping from a data block offset to the corresponding filter.
+
+## "stats" Meta Block
+
+This meta block contains a bunch of stats. The key is the name
+of the statistic. The value contains the statistic.
+
+TODO(postrelease): record following stats.
+
+ data size
+ index size
+ key size (uncompressed)
+ value size (uncompressed)
+ number of entries
+ number of data blocks
diff --git a/src/leveldb/doc/table_format.txt b/src/leveldb/doc/table_format.txt
deleted file mode 100644
index ca8f9b4460..0000000000
--- a/src/leveldb/doc/table_format.txt
+++ /dev/null
@@ -1,104 +0,0 @@
-File format
-===========
-
- <beginning_of_file>
- [data block 1]
- [data block 2]
- ...
- [data block N]
- [meta block 1]
- ...
- [meta block K]
- [metaindex block]
- [index block]
- [Footer] (fixed size; starts at file_size - sizeof(Footer))
- <end_of_file>
-
-The file contains internal pointers. Each such pointer is called
-a BlockHandle and contains the following information:
- offset: varint64
- size: varint64
-See https://developers.google.com/protocol-buffers/docs/encoding#varints
-for an explanation of varint64 format.
-
-(1) The sequence of key/value pairs in the file are stored in sorted
-order and partitioned into a sequence of data blocks. These blocks
-come one after another at the beginning of the file. Each data block
-is formatted according to the code in block_builder.cc, and then
-optionally compressed.
-
-(2) After the data blocks we store a bunch of meta blocks. The
-supported meta block types are described below. More meta block types
-may be added in the future. Each meta block is again formatted using
-block_builder.cc and then optionally compressed.
-
-(3) A "metaindex" block. It contains one entry for every other meta
-block where the key is the name of the meta block and the value is a
-BlockHandle pointing to that meta block.
-
-(4) An "index" block. This block contains one entry per data block,
-where the key is a string >= last key in that data block and before
-the first key in the successive data block. The value is the
-BlockHandle for the data block.
-
-(6) At the very end of the file is a fixed length footer that contains
-the BlockHandle of the metaindex and index blocks as well as a magic number.
- metaindex_handle: char[p]; // Block handle for metaindex
- index_handle: char[q]; // Block handle for index
- padding: char[40-p-q]; // zeroed bytes to make fixed length
- // (40==2*BlockHandle::kMaxEncodedLength)
- magic: fixed64; // == 0xdb4775248b80fb57 (little-endian)
-
-"filter" Meta Block
--------------------
-
-If a "FilterPolicy" was specified when the database was opened, a
-filter block is stored in each table. The "metaindex" block contains
-an entry that maps from "filter.<N>" to the BlockHandle for the filter
-block where "<N>" is the string returned by the filter policy's
-"Name()" method.
-
-The filter block stores a sequence of filters, where filter i contains
-the output of FilterPolicy::CreateFilter() on all keys that are stored
-in a block whose file offset falls within the range
-
- [ i*base ... (i+1)*base-1 ]
-
-Currently, "base" is 2KB. So for example, if blocks X and Y start in
-the range [ 0KB .. 2KB-1 ], all of the keys in X and Y will be
-converted to a filter by calling FilterPolicy::CreateFilter(), and the
-resulting filter will be stored as the first filter in the filter
-block.
-
-The filter block is formatted as follows:
-
- [filter 0]
- [filter 1]
- [filter 2]
- ...
- [filter N-1]
-
- [offset of filter 0] : 4 bytes
- [offset of filter 1] : 4 bytes
- [offset of filter 2] : 4 bytes
- ...
- [offset of filter N-1] : 4 bytes
-
- [offset of beginning of offset array] : 4 bytes
- lg(base) : 1 byte
-
-The offset array at the end of the filter block allows efficient
-mapping from a data block offset to the corresponding filter.
-
-"stats" Meta Block
-------------------
-
-This meta block contains a bunch of stats. The key is the name
-of the statistic. The value contains the statistic.
-TODO(postrelease): record following stats.
- data size
- index size
- key size (uncompressed)
- value size (uncompressed)
- number of entries
- number of data blocks
diff --git a/src/leveldb/include/leveldb/db.h b/src/leveldb/include/leveldb/db.h
index 9752cbad51..bfab10a0b7 100644
--- a/src/leveldb/include/leveldb/db.h
+++ b/src/leveldb/include/leveldb/db.h
@@ -14,7 +14,7 @@ namespace leveldb {
// Update Makefile if you change these
static const int kMajorVersion = 1;
-static const int kMinorVersion = 19;
+static const int kMinorVersion = 20;
struct Options;
struct ReadOptions;
diff --git a/src/leveldb/include/leveldb/options.h b/src/leveldb/include/leveldb/options.h
index 83a1ef39a4..976e38122a 100644
--- a/src/leveldb/include/leveldb/options.h
+++ b/src/leveldb/include/leveldb/options.h
@@ -112,6 +112,18 @@ struct Options {
// Default: 16
int block_restart_interval;
+ // Leveldb will write up to this amount of bytes to a file before
+ // switching to a new one.
+ // Most clients should leave this parameter alone. However if your
+ // filesystem is more efficient with larger files, you could
+ // consider increasing the value. The downside will be longer
+ // compactions and hence longer latency/performance hiccups.
+ // Another reason to increase this parameter might be when you are
+ // initially populating a large database.
+ //
+ // Default: 2MB
+ size_t max_file_size;
+
// Compress blocks using the specified compression algorithm. This
// parameter can be changed dynamically.
//
diff --git a/src/leveldb/port/atomic_pointer.h b/src/leveldb/port/atomic_pointer.h
index 1c4c7aafc6..d79a02230d 100644
--- a/src/leveldb/port/atomic_pointer.h
+++ b/src/leveldb/port/atomic_pointer.h
@@ -46,6 +46,30 @@
namespace leveldb {
namespace port {
+// AtomicPointer based on <cstdatomic> if available
+#if defined(LEVELDB_ATOMIC_PRESENT)
+class AtomicPointer {
+ private:
+ std::atomic<void*> rep_;
+ public:
+ AtomicPointer() { }
+ explicit AtomicPointer(void* v) : rep_(v) { }
+ inline void* Acquire_Load() const {
+ return rep_.load(std::memory_order_acquire);
+ }
+ inline void Release_Store(void* v) {
+ rep_.store(v, std::memory_order_release);
+ }
+ inline void* NoBarrier_Load() const {
+ return rep_.load(std::memory_order_relaxed);
+ }
+ inline void NoBarrier_Store(void* v) {
+ rep_.store(v, std::memory_order_relaxed);
+ }
+};
+
+#else
+
// Define MemoryBarrier() if available
// Windows on x86
#if defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY)
@@ -142,28 +166,6 @@ class AtomicPointer {
}
};
-// AtomicPointer based on <cstdatomic>
-#elif defined(LEVELDB_ATOMIC_PRESENT)
-class AtomicPointer {
- private:
- std::atomic<void*> rep_;
- public:
- AtomicPointer() { }
- explicit AtomicPointer(void* v) : rep_(v) { }
- inline void* Acquire_Load() const {
- return rep_.load(std::memory_order_acquire);
- }
- inline void Release_Store(void* v) {
- rep_.store(v, std::memory_order_release);
- }
- inline void* NoBarrier_Load() const {
- return rep_.load(std::memory_order_relaxed);
- }
- inline void NoBarrier_Store(void* v) {
- rep_.store(v, std::memory_order_relaxed);
- }
-};
-
// Atomic pointer based on sparc memory barriers
#elif defined(__sparcv9) && defined(__GNUC__)
class AtomicPointer {
@@ -229,6 +231,7 @@ class AtomicPointer {
#error Please implement AtomicPointer for this platform.
#endif
+#endif
#undef LEVELDB_HAVE_MEMORY_BARRIER
#undef ARCH_CPU_X86_FAMILY
diff --git a/src/leveldb/port/port_example.h b/src/leveldb/port/port_example.h
index ab9e489b32..5b1d027de5 100644
--- a/src/leveldb/port/port_example.h
+++ b/src/leveldb/port/port_example.h
@@ -129,6 +129,16 @@ extern bool Snappy_Uncompress(const char* input_data, size_t input_length,
// The concatenation of all "data[0,n-1]" fragments is the heap profile.
extern bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg);
+// Determine whether a working accelerated crc32 implementation exists
+// Returns true if AcceleratedCRC32C is safe to call
+bool HasAcceleratedCRC32C();
+
+// Extend the CRC to include the first n bytes of buf.
+//
+// Returns zero if the CRC cannot be extended using acceleration, else returns
+// the newly extended CRC value (which may also be zero).
+uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size);
+
} // namespace port
} // namespace leveldb
diff --git a/src/leveldb/port/port_posix.cc b/src/leveldb/port/port_posix.cc
index 30e8007ae3..ec39e92195 100644
--- a/src/leveldb/port/port_posix.cc
+++ b/src/leveldb/port/port_posix.cc
@@ -8,6 +8,10 @@
#include <stdio.h>
#include <string.h>
+#if (defined(__x86_64__) || defined(__i386__)) && defined(__GNUC__)
+#include <cpuid.h>
+#endif
+
namespace leveldb {
namespace port {
@@ -49,5 +53,15 @@ void InitOnce(OnceType* once, void (*initializer)()) {
PthreadCall("once", pthread_once(once, initializer));
}
+bool HasAcceleratedCRC32C() {
+#if (defined(__x86_64__) || defined(__i386__)) && defined(__GNUC__)
+ unsigned int eax, ebx, ecx, edx;
+ __get_cpuid(1, &eax, &ebx, &ecx, &edx);
+ return (ecx & (1 << 20)) != 0;
+#else
+ return false;
+#endif
+}
+
} // namespace port
} // namespace leveldb
diff --git a/src/leveldb/port/port_posix.h b/src/leveldb/port/port_posix.h
index ccca9939d3..d85fa5d63f 100644
--- a/src/leveldb/port/port_posix.h
+++ b/src/leveldb/port/port_posix.h
@@ -152,6 +152,9 @@ inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) {
return false;
}
+bool HasAcceleratedCRC32C();
+uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size);
+
} // namespace port
} // namespace leveldb
diff --git a/src/leveldb/port/port_posix_sse.cc b/src/leveldb/port/port_posix_sse.cc
new file mode 100644
index 0000000000..2d49c21dd8
--- /dev/null
+++ b/src/leveldb/port/port_posix_sse.cc
@@ -0,0 +1,110 @@
+// Copyright 2016 The LevelDB Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file. See the AUTHORS file for names of contributors.
+//
+// A portable implementation of crc32c, optimized to handle
+// four bytes at a time.
+//
+// In a separate source file to allow this accelerated CRC32C function to be
+// compiled with the appropriate compiler flags to enable x86 SSE 4.2
+// instructions.
+
+#include <stdint.h>
+#include <string.h>
+#include "port/port.h"
+
+#if defined(LEVELDB_PLATFORM_POSIX_SSE)
+
+#if defined(_MSC_VER)
+#include <intrin.h>
+#elif defined(__GNUC__) && defined(__SSE4_2__)
+#include <nmmintrin.h>
+#endif
+
+#endif // defined(LEVELDB_PLATFORM_POSIX_SSE)
+
+namespace leveldb {
+namespace port {
+
+#if defined(LEVELDB_PLATFORM_POSIX_SSE)
+
+// Used to fetch a naturally-aligned 32-bit word in little endian byte-order
+static inline uint32_t LE_LOAD32(const uint8_t *p) {
+ // SSE is x86 only, so ensured that |p| is always little-endian.
+ uint32_t word;
+ memcpy(&word, p, sizeof(word));
+ return word;
+}
+
+#if defined(_M_X64) || defined(__x86_64__) // LE_LOAD64 is only used on x64.
+
+// Used to fetch a naturally-aligned 64-bit word in little endian byte-order
+static inline uint64_t LE_LOAD64(const uint8_t *p) {
+ uint64_t dword;
+ memcpy(&dword, p, sizeof(dword));
+ return dword;
+}
+
+#endif // defined(_M_X64) || defined(__x86_64__)
+
+#endif // defined(LEVELDB_PLATFORM_POSIX_SSE)
+
+// For further improvements see Intel publication at:
+// http://download.intel.com/design/intarch/papers/323405.pdf
+uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size) {
+#if !defined(LEVELDB_PLATFORM_POSIX_SSE)
+ return 0;
+#else
+
+ const uint8_t *p = reinterpret_cast<const uint8_t *>(buf);
+ const uint8_t *e = p + size;
+ uint32_t l = crc ^ 0xffffffffu;
+
+#define STEP1 do { \
+ l = _mm_crc32_u8(l, *p++); \
+} while (0)
+#define STEP4 do { \
+ l = _mm_crc32_u32(l, LE_LOAD32(p)); \
+ p += 4; \
+} while (0)
+#define STEP8 do { \
+ l = _mm_crc32_u64(l, LE_LOAD64(p)); \
+ p += 8; \
+} while (0)
+
+ if (size > 16) {
+ // Process unaligned bytes
+ for (unsigned int i = reinterpret_cast<uintptr_t>(p) % 8; i; --i) {
+ STEP1;
+ }
+
+ // _mm_crc32_u64 is only available on x64.
+#if defined(_M_X64) || defined(__x86_64__)
+ // Process 8 bytes at a time
+ while ((e-p) >= 8) {
+ STEP8;
+ }
+ // Process 4 bytes at a time
+ if ((e-p) >= 4) {
+ STEP4;
+ }
+#else // !(defined(_M_X64) || defined(__x86_64__))
+ // Process 4 bytes at a time
+ while ((e-p) >= 4) {
+ STEP4;
+ }
+#endif // defined(_M_X64) || defined(__x86_64__)
+ }
+ // Process the last few bytes
+ while (p != e) {
+ STEP1;
+ }
+#undef STEP8
+#undef STEP4
+#undef STEP1
+ return l ^ 0xffffffffu;
+#endif // defined(LEVELDB_PLATFORM_POSIX_SSE)
+}
+
+} // namespace port
+} // namespace leveldb
diff --git a/src/leveldb/port/port_win.cc b/src/leveldb/port/port_win.cc
index 1b0f060a19..1be9e8d5b0 100644
--- a/src/leveldb/port/port_win.cc
+++ b/src/leveldb/port/port_win.cc
@@ -32,6 +32,7 @@
#include <windows.h>
#include <cassert>
+#include <intrin.h>
namespace leveldb {
namespace port {
@@ -143,5 +144,15 @@ void AtomicPointer::NoBarrier_Store(void* v) {
rep_ = v;
}
+bool HasAcceleratedCRC32C() {
+#if defined(__x86_64__) || defined(__i386__)
+ int cpu_info[4];
+ __cpuid(cpu_info, 1);
+ return (cpu_info[2] & (1 << 20)) != 0;
+#else
+ return false;
+#endif
+}
+
}
}
diff --git a/src/leveldb/port/port_win.h b/src/leveldb/port/port_win.h
index 45bf2f0ea7..e8bf46ef27 100644
--- a/src/leveldb/port/port_win.h
+++ b/src/leveldb/port/port_win.h
@@ -168,6 +168,9 @@ inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) {
return false;
}
+bool HasAcceleratedCRC32C();
+uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size);
+
}
}
diff --git a/src/leveldb/table/filter_block.cc b/src/leveldb/table/filter_block.cc
index 4e78b954f8..1ed5134170 100644
--- a/src/leveldb/table/filter_block.cc
+++ b/src/leveldb/table/filter_block.cc
@@ -9,7 +9,7 @@
namespace leveldb {
-// See doc/table_format.txt for an explanation of the filter block format.
+// See doc/table_format.md for an explanation of the filter block format.
// Generate new filter every 2KB of data
static const size_t kFilterBaseLg = 11;
diff --git a/src/leveldb/util/crc32c.cc b/src/leveldb/util/crc32c.cc
index 6db9e77077..b3f40eeeed 100644
--- a/src/leveldb/util/crc32c.cc
+++ b/src/leveldb/util/crc32c.cc
@@ -8,6 +8,8 @@
#include "util/crc32c.h"
#include <stdint.h>
+
+#include "port/port.h"
#include "util/coding.h"
namespace leveldb {
@@ -283,7 +285,27 @@ static inline uint32_t LE_LOAD32(const uint8_t *p) {
return DecodeFixed32(reinterpret_cast<const char*>(p));
}
+// Determine if the CPU running this program can accelerate the CRC32C
+// calculation.
+static bool CanAccelerateCRC32C() {
+ if (!port::HasAcceleratedCRC32C())
+ return false;
+
+ // Double-check that the accelerated implementation functions correctly.
+ // port::AcceleretedCRC32C returns zero when unable to accelerate.
+ static const char kTestCRCBuffer[] = "TestCRCBuffer";
+ static const char kBufSize = sizeof(kTestCRCBuffer) - 1;
+ static const uint32_t kTestCRCValue = 0xdcbc59fa;
+
+ return port::AcceleratedCRC32C(0, kTestCRCBuffer, kBufSize) == kTestCRCValue;
+}
+
uint32_t Extend(uint32_t crc, const char* buf, size_t size) {
+ static bool accelerate = CanAccelerateCRC32C();
+ if (accelerate) {
+ return port::AcceleratedCRC32C(crc, buf, size);
+ }
+
const uint8_t *p = reinterpret_cast<const uint8_t *>(buf);
const uint8_t *e = p + size;
uint32_t l = crc ^ 0xffffffffu;
diff --git a/src/leveldb/util/env_posix.cc b/src/leveldb/util/env_posix.cc
index e0fca52f46..dd852af354 100644
--- a/src/leveldb/util/env_posix.cc
+++ b/src/leveldb/util/env_posix.cc
@@ -11,12 +11,14 @@
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
+#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <deque>
+#include <limits>
#include <set>
#include "leveldb/env.h"
#include "leveldb/slice.h"
@@ -24,15 +26,70 @@
#include "util/logging.h"
#include "util/mutexlock.h"
#include "util/posix_logger.h"
+#include "util/env_posix_test_helper.h"
namespace leveldb {
namespace {
+static int open_read_only_file_limit = -1;
+static int mmap_limit = -1;
+
static Status IOError(const std::string& context, int err_number) {
return Status::IOError(context, strerror(err_number));
}
+// Helper class to limit resource usage to avoid exhaustion.
+// Currently used to limit read-only file descriptors and mmap file usage
+// so that we do not end up running out of file descriptors, virtual memory,
+// or running into kernel performance problems for very large databases.
+class Limiter {
+ public:
+ // Limit maximum number of resources to |n|.
+ Limiter(intptr_t n) {
+ SetAllowed(n);
+ }
+
+ // If another resource is available, acquire it and return true.
+ // Else return false.
+ bool Acquire() {
+ if (GetAllowed() <= 0) {
+ return false;
+ }
+ MutexLock l(&mu_);
+ intptr_t x = GetAllowed();
+ if (x <= 0) {
+ return false;
+ } else {
+ SetAllowed(x - 1);
+ return true;
+ }
+ }
+
+ // Release a resource acquired by a previous call to Acquire() that returned
+ // true.
+ void Release() {
+ MutexLock l(&mu_);
+ SetAllowed(GetAllowed() + 1);
+ }
+
+ private:
+ port::Mutex mu_;
+ port::AtomicPointer allowed_;
+
+ intptr_t GetAllowed() const {
+ return reinterpret_cast<intptr_t>(allowed_.Acquire_Load());
+ }
+
+ // REQUIRES: mu_ must be held
+ void SetAllowed(intptr_t v) {
+ allowed_.Release_Store(reinterpret_cast<void*>(v));
+ }
+
+ Limiter(const Limiter&);
+ void operator=(const Limiter&);
+};
+
class PosixSequentialFile: public SequentialFile {
private:
std::string filename_;
@@ -70,73 +127,51 @@ class PosixSequentialFile: public SequentialFile {
class PosixRandomAccessFile: public RandomAccessFile {
private:
std::string filename_;
+ bool temporary_fd_; // If true, fd_ is -1 and we open on every read.
int fd_;
+ Limiter* limiter_;
public:
- PosixRandomAccessFile(const std::string& fname, int fd)
- : filename_(fname), fd_(fd) { }
- virtual ~PosixRandomAccessFile() { close(fd_); }
+ PosixRandomAccessFile(const std::string& fname, int fd, Limiter* limiter)
+ : filename_(fname), fd_(fd), limiter_(limiter) {
+ temporary_fd_ = !limiter->Acquire();
+ if (temporary_fd_) {
+ // Open file on every access.
+ close(fd_);
+ fd_ = -1;
+ }
+ }
+
+ virtual ~PosixRandomAccessFile() {
+ if (!temporary_fd_) {
+ close(fd_);
+ limiter_->Release();
+ }
+ }
virtual Status Read(uint64_t offset, size_t n, Slice* result,
char* scratch) const {
+ int fd = fd_;
+ if (temporary_fd_) {
+ fd = open(filename_.c_str(), O_RDONLY);
+ if (fd < 0) {
+ return IOError(filename_, errno);
+ }
+ }
+
Status s;
- ssize_t r = pread(fd_, scratch, n, static_cast<off_t>(offset));
+ ssize_t r = pread(fd, scratch, n, static_cast<off_t>(offset));
*result = Slice(scratch, (r < 0) ? 0 : r);
if (r < 0) {
// An error: return a non-ok status
s = IOError(filename_, errno);
}
- return s;
- }
-};
-
-// Helper class to limit mmap file usage so that we do not end up
-// running out virtual memory or running into kernel performance
-// problems for very large databases.
-class MmapLimiter {
- public:
- // Up to 1000 mmaps for 64-bit binaries; none for smaller pointer sizes.
- MmapLimiter() {
- SetAllowed(sizeof(void*) >= 8 ? 1000 : 0);
- }
-
- // If another mmap slot is available, acquire it and return true.
- // Else return false.
- bool Acquire() {
- if (GetAllowed() <= 0) {
- return false;
- }
- MutexLock l(&mu_);
- intptr_t x = GetAllowed();
- if (x <= 0) {
- return false;
- } else {
- SetAllowed(x - 1);
- return true;
+ if (temporary_fd_) {
+ // Close the temporary file descriptor opened earlier.
+ close(fd);
}
+ return s;
}
-
- // Release a slot acquired by a previous call to Acquire() that returned true.
- void Release() {
- MutexLock l(&mu_);
- SetAllowed(GetAllowed() + 1);
- }
-
- private:
- port::Mutex mu_;
- port::AtomicPointer allowed_;
-
- intptr_t GetAllowed() const {
- return reinterpret_cast<intptr_t>(allowed_.Acquire_Load());
- }
-
- // REQUIRES: mu_ must be held
- void SetAllowed(intptr_t v) {
- allowed_.Release_Store(reinterpret_cast<void*>(v));
- }
-
- MmapLimiter(const MmapLimiter&);
- void operator=(const MmapLimiter&);
};
// mmap() based random-access
@@ -145,12 +180,12 @@ class PosixMmapReadableFile: public RandomAccessFile {
std::string filename_;
void* mmapped_region_;
size_t length_;
- MmapLimiter* limiter_;
+ Limiter* limiter_;
public:
// base[0,length-1] contains the mmapped contents of the file.
PosixMmapReadableFile(const std::string& fname, void* base, size_t length,
- MmapLimiter* limiter)
+ Limiter* limiter)
: filename_(fname), mmapped_region_(base), length_(length),
limiter_(limiter) {
}
@@ -231,7 +266,7 @@ class PosixWritableFile : public WritableFile {
if (fd < 0) {
s = IOError(dir, errno);
} else {
- if (fsync(fd) < 0) {
+ if (fsync(fd) < 0 && errno != EINVAL) {
s = IOError(dir, errno);
}
close(fd);
@@ -333,7 +368,7 @@ class PosixEnv : public Env {
mmap_limit_.Release();
}
} else {
- *result = new PosixRandomAccessFile(fname, fd);
+ *result = new PosixRandomAccessFile(fname, fd, &fd_limit_);
}
return s;
}
@@ -533,10 +568,42 @@ class PosixEnv : public Env {
BGQueue queue_;
PosixLockTable locks_;
- MmapLimiter mmap_limit_;
+ Limiter mmap_limit_;
+ Limiter fd_limit_;
};
-PosixEnv::PosixEnv() : started_bgthread_(false) {
+// Return the maximum number of concurrent mmaps.
+static int MaxMmaps() {
+ if (mmap_limit >= 0) {
+ return mmap_limit;
+ }
+ // Up to 1000 mmaps for 64-bit binaries; none for smaller pointer sizes.
+ mmap_limit = sizeof(void*) >= 8 ? 1000 : 0;
+ return mmap_limit;
+}
+
+// Return the maximum number of read-only files to keep open.
+static intptr_t MaxOpenFiles() {
+ if (open_read_only_file_limit >= 0) {
+ return open_read_only_file_limit;
+ }
+ struct rlimit rlim;
+ if (getrlimit(RLIMIT_NOFILE, &rlim)) {
+ // getrlimit failed, fallback to hard-coded default.
+ open_read_only_file_limit = 50;
+ } else if (rlim.rlim_cur == RLIM_INFINITY) {
+ open_read_only_file_limit = std::numeric_limits<int>::max();
+ } else {
+ // Allow use of 20% of available file descriptors for read-only files.
+ open_read_only_file_limit = rlim.rlim_cur / 5;
+ }
+ return open_read_only_file_limit;
+}
+
+PosixEnv::PosixEnv()
+ : started_bgthread_(false),
+ mmap_limit_(MaxMmaps()),
+ fd_limit_(MaxOpenFiles()) {
PthreadCall("mutex_init", pthread_mutex_init(&mu_, NULL));
PthreadCall("cvar_init", pthread_cond_init(&bgsignal_, NULL));
}
@@ -611,6 +678,16 @@ static pthread_once_t once = PTHREAD_ONCE_INIT;
static Env* default_env;
static void InitDefaultEnv() { default_env = new PosixEnv; }
+void EnvPosixTestHelper::SetReadOnlyFDLimit(int limit) {
+ assert(default_env == NULL);
+ open_read_only_file_limit = limit;
+}
+
+void EnvPosixTestHelper::SetReadOnlyMMapLimit(int limit) {
+ assert(default_env == NULL);
+ mmap_limit = limit;
+}
+
Env* Env::Default() {
pthread_once(&once, InitDefaultEnv);
return default_env;
diff --git a/src/leveldb/util/env_posix_test.cc b/src/leveldb/util/env_posix_test.cc
new file mode 100644
index 0000000000..295f8ae440
--- /dev/null
+++ b/src/leveldb/util/env_posix_test.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file. See the AUTHORS file for names of contributors.
+
+#include "leveldb/env.h"
+
+#include "port/port.h"
+#include "util/testharness.h"
+#include "util/env_posix_test_helper.h"
+
+namespace leveldb {
+
+static const int kDelayMicros = 100000;
+static const int kReadOnlyFileLimit = 4;
+static const int kMMapLimit = 4;
+
+class EnvPosixTest {
+ public:
+ Env* env_;
+ EnvPosixTest() : env_(Env::Default()) { }
+
+ static void SetFileLimits(int read_only_file_limit, int mmap_limit) {
+ EnvPosixTestHelper::SetReadOnlyFDLimit(read_only_file_limit);
+ EnvPosixTestHelper::SetReadOnlyMMapLimit(mmap_limit);
+ }
+};
+
+TEST(EnvPosixTest, TestOpenOnRead) {
+ // Write some test data to a single file that will be opened |n| times.
+ std::string test_dir;
+ ASSERT_OK(env_->GetTestDirectory(&test_dir));
+ std::string test_file = test_dir + "/open_on_read.txt";
+
+ FILE* f = fopen(test_file.c_str(), "w");
+ ASSERT_TRUE(f != NULL);
+ const char kFileData[] = "abcdefghijklmnopqrstuvwxyz";
+ fputs(kFileData, f);
+ fclose(f);
+
+ // Open test file some number above the sum of the two limits to force
+ // open-on-read behavior of POSIX Env leveldb::RandomAccessFile.
+ const int kNumFiles = kReadOnlyFileLimit + kMMapLimit + 5;
+ leveldb::RandomAccessFile* files[kNumFiles] = {0};
+ for (int i = 0; i < kNumFiles; i++) {
+ ASSERT_OK(env_->NewRandomAccessFile(test_file, &files[i]));
+ }
+ char scratch;
+ Slice read_result;
+ for (int i = 0; i < kNumFiles; i++) {
+ ASSERT_OK(files[i]->Read(i, 1, &read_result, &scratch));
+ ASSERT_EQ(kFileData[i], read_result[0]);
+ }
+ for (int i = 0; i < kNumFiles; i++) {
+ delete files[i];
+ }
+ ASSERT_OK(env_->DeleteFile(test_file));
+}
+
+} // namespace leveldb
+
+int main(int argc, char** argv) {
+ // All tests currently run with the same read-only file limits.
+ leveldb::EnvPosixTest::SetFileLimits(leveldb::kReadOnlyFileLimit,
+ leveldb::kMMapLimit);
+ return leveldb::test::RunAllTests();
+}
diff --git a/src/leveldb/util/env_posix_test_helper.h b/src/leveldb/util/env_posix_test_helper.h
new file mode 100644
index 0000000000..0386960598
--- /dev/null
+++ b/src/leveldb/util/env_posix_test_helper.h
@@ -0,0 +1,28 @@
+// Copyright 2017 The LevelDB Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file. See the AUTHORS file for names of contributors.
+
+#ifndef STORAGE_LEVELDB_UTIL_ENV_POSIX_TEST_HELPER_H_
+#define STORAGE_LEVELDB_UTIL_ENV_POSIX_TEST_HELPER_H_
+
+namespace leveldb {
+
+class EnvPosixTest;
+
+// A helper for the POSIX Env to facilitate testing.
+class EnvPosixTestHelper {
+ private:
+ friend class EnvPosixTest;
+
+ // Set the maximum number of read-only files that will be opened.
+ // Must be called before creating an Env.
+ static void SetReadOnlyFDLimit(int limit);
+
+ // Set the maximum number of read-only files that will be mapped via mmap.
+ // Must be called before creating an Env.
+ static void SetReadOnlyMMapLimit(int limit);
+};
+
+} // namespace leveldb
+
+#endif // STORAGE_LEVELDB_UTIL_ENV_POSIX_TEST_HELPER_H_
diff --git a/src/leveldb/util/env_test.cc b/src/leveldb/util/env_test.cc
index b72cb44384..839ae56a1a 100644
--- a/src/leveldb/util/env_test.cc
+++ b/src/leveldb/util/env_test.cc
@@ -10,29 +10,31 @@
namespace leveldb {
static const int kDelayMicros = 100000;
+static const int kReadOnlyFileLimit = 4;
+static const int kMMapLimit = 4;
-class EnvPosixTest {
+class EnvTest {
private:
port::Mutex mu_;
std::string events_;
public:
Env* env_;
- EnvPosixTest() : env_(Env::Default()) { }
+ EnvTest() : env_(Env::Default()) { }
};
static void SetBool(void* ptr) {
reinterpret_cast<port::AtomicPointer*>(ptr)->NoBarrier_Store(ptr);
}
-TEST(EnvPosixTest, RunImmediately) {
+TEST(EnvTest, RunImmediately) {
port::AtomicPointer called (NULL);
env_->Schedule(&SetBool, &called);
- Env::Default()->SleepForMicroseconds(kDelayMicros);
+ env_->SleepForMicroseconds(kDelayMicros);
ASSERT_TRUE(called.NoBarrier_Load() != NULL);
}
-TEST(EnvPosixTest, RunMany) {
+TEST(EnvTest, RunMany) {
port::AtomicPointer last_id (NULL);
struct CB {
@@ -59,7 +61,7 @@ TEST(EnvPosixTest, RunMany) {
env_->Schedule(&CB::Run, &cb3);
env_->Schedule(&CB::Run, &cb4);
- Env::Default()->SleepForMicroseconds(kDelayMicros);
+ env_->SleepForMicroseconds(kDelayMicros);
void* cur = last_id.Acquire_Load();
ASSERT_EQ(4, reinterpret_cast<uintptr_t>(cur));
}
@@ -78,7 +80,7 @@ static void ThreadBody(void* arg) {
s->mu.Unlock();
}
-TEST(EnvPosixTest, StartThread) {
+TEST(EnvTest, StartThread) {
State state;
state.val = 0;
state.num_running = 3;
@@ -92,7 +94,7 @@ TEST(EnvPosixTest, StartThread) {
if (num == 0) {
break;
}
- Env::Default()->SleepForMicroseconds(kDelayMicros);
+ env_->SleepForMicroseconds(kDelayMicros);
}
ASSERT_EQ(state.val, 3);
}
diff --git a/src/leveldb/util/env_win.cc b/src/leveldb/util/env_win.cc
index b074b7579e..d32c4e676c 100644
--- a/src/leveldb/util/env_win.cc
+++ b/src/leveldb/util/env_win.cc
@@ -1,7 +1,7 @@
// This file contains source that originates from:
// http://code.google.com/p/leveldbwin/source/browse/trunk/win32_impl_src/env_win32.h
// http://code.google.com/p/leveldbwin/source/browse/trunk/win32_impl_src/port_win32.cc
-// Those files dont' have any explict license headers but the
+// Those files don't have any explicit license headers but the
// project (http://code.google.com/p/leveldbwin/) lists the 'New BSD License'
// as the license.
#if defined(LEVELDB_PLATFORM_WINDOWS)
@@ -355,11 +355,13 @@ BOOL Win32SequentialFile::_Init()
ToWidePath(_filename, path);
_hFile = CreateFileW(path.c_str(),
GENERIC_READ,
- FILE_SHARE_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
+ if (_hFile == INVALID_HANDLE_VALUE)
+ _hFile = NULL;
return _hFile ? TRUE : FALSE;
}
@@ -403,7 +405,7 @@ BOOL Win32RandomAccessFile::_Init( LPCWSTR path )
{
BOOL bRet = FALSE;
if(!_hFile)
- _hFile = ::CreateFileW(path,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
+ _hFile = ::CreateFileW(path,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,NULL);
if(!_hFile || _hFile == INVALID_HANDLE_VALUE )
_hFile = NULL;
@@ -669,7 +671,7 @@ Status Win32Env::GetFileSize( const std::string& fname, uint64_t* file_size )
ToWidePath(ModifyPath(path), wpath);
HANDLE file = ::CreateFileW(wpath.c_str(),
- GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
+ GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
LARGE_INTEGER li;
if(::GetFileSizeEx(file,&li)){
*file_size = (uint64_t)li.QuadPart;
diff --git a/src/leveldb/util/logging.cc b/src/leveldb/util/logging.cc
index ca6b324403..db6160c8f1 100644
--- a/src/leveldb/util/logging.cc
+++ b/src/leveldb/util/logging.cc
@@ -49,7 +49,7 @@ bool ConsumeDecimalNumber(Slice* in, uint64_t* val) {
uint64_t v = 0;
int digits = 0;
while (!in->empty()) {
- char c = (*in)[0];
+ unsigned char c = (*in)[0];
if (c >= '0' && c <= '9') {
++digits;
const int delta = (c - '0');
diff --git a/src/leveldb/util/options.cc b/src/leveldb/util/options.cc
index 8b618fb1ae..b5e6227613 100644
--- a/src/leveldb/util/options.cc
+++ b/src/leveldb/util/options.cc
@@ -21,6 +21,7 @@ Options::Options()
block_cache(NULL),
block_size(4096),
block_restart_interval(16),
+ max_file_size(2<<20),
compression(kSnappyCompression),
reuse_logs(false),
filter_policy(NULL) {
diff --git a/src/limitedmap.h b/src/limitedmap.h
index e9dcb6defd..7afc8b458d 100644
--- a/src/limitedmap.h
+++ b/src/limitedmap.h
@@ -27,7 +27,7 @@ protected:
size_type nMaxSize;
public:
- limitedmap(size_type nMaxSizeIn)
+ explicit limitedmap(size_type nMaxSizeIn)
{
assert(nMaxSizeIn > 0);
nMaxSize = nMaxSizeIn;
diff --git a/src/memusage.h b/src/memusage.h
index 81e8702954..93fd6a0eb5 100644
--- a/src/memusage.h
+++ b/src/memusage.h
@@ -12,10 +12,9 @@
#include <map>
#include <set>
#include <vector>
+#include <unordered_map>
+#include <unordered_set>
-#include <boost/foreach.hpp>
-#include <boost/unordered_set.hpp>
-#include <boost/unordered_map.hpp>
namespace memusage
{
@@ -146,25 +145,23 @@ static inline size_t DynamicUsage(const std::shared_ptr<X>& p)
return p ? MallocUsage(sizeof(X)) + MallocUsage(sizeof(stl_shared_counter)) : 0;
}
-// Boost data structures
-
template<typename X>
-struct boost_unordered_node : private X
+struct unordered_node : private X
{
private:
void* ptr;
};
template<typename X, typename Y>
-static inline size_t DynamicUsage(const boost::unordered_set<X, Y>& s)
+static inline size_t DynamicUsage(const std::unordered_set<X, Y>& s)
{
- return MallocUsage(sizeof(boost_unordered_node<X>)) * s.size() + MallocUsage(sizeof(void*) * s.bucket_count());
+ return MallocUsage(sizeof(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)
+static inline size_t DynamicUsage(const std::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());
+ return MallocUsage(sizeof(unordered_node<std::pair<const X, Y> >)) * m.size() + MallocUsage(sizeof(void*) * m.bucket_count());
}
}
diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp
index 86c8172a31..3f07b4dac4 100644
--- a/src/merkleblock.cpp
+++ b/src/merkleblock.cpp
@@ -9,14 +9,13 @@
#include "consensus/consensus.h"
#include "utilstrencodings.h"
-using namespace std;
-CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter& filter)
+CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter* filter, const std::set<uint256>* txids)
{
header = block.GetBlockHeader();
- vector<bool> vMatch;
- vector<uint256> vHashes;
+ std::vector<bool> vMatch;
+ std::vector<uint256> vHashes;
vMatch.reserve(block.vtx.size());
vHashes.reserve(block.vtx.size());
@@ -24,36 +23,14 @@ CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter& filter)
for (unsigned int i = 0; i < block.vtx.size(); i++)
{
const uint256& hash = block.vtx[i]->GetHash();
- if (filter.IsRelevantAndUpdate(*block.vtx[i]))
- {
+ if (txids && txids->count(hash)) {
vMatch.push_back(true);
- vMatchedTxn.push_back(make_pair(i, hash));
- }
- else
- vMatch.push_back(false);
- vHashes.push_back(hash);
- }
-
- txn = CPartialMerkleTree(vHashes, vMatch);
-}
-
-CMerkleBlock::CMerkleBlock(const CBlock& block, const std::set<uint256>& txids)
-{
- header = block.GetBlockHeader();
-
- vector<bool> vMatch;
- vector<uint256> vHashes;
-
- vMatch.reserve(block.vtx.size());
- vHashes.reserve(block.vtx.size());
-
- for (unsigned int i = 0; i < block.vtx.size(); i++)
- {
- const uint256& hash = block.vtx[i]->GetHash();
- if (txids.count(hash))
+ } else if (filter && filter->IsRelevantAndUpdate(*block.vtx[i])) {
vMatch.push_back(true);
- else
+ vMatchedTxn.emplace_back(i, hash);
+ } else {
vMatch.push_back(false);
+ }
vHashes.push_back(hash);
}
@@ -61,13 +38,16 @@ CMerkleBlock::CMerkleBlock(const CBlock& block, const std::set<uint256>& txids)
}
uint256 CPartialMerkleTree::CalcHash(int height, unsigned int pos, const std::vector<uint256> &vTxid) {
+ //we can never have zero txs in a merkle block, we always need the coinbase tx
+ //if we do not have this assert, we can hit a memory access violation when indexing into vTxid
+ assert(vTxid.size() != 0);
if (height == 0) {
// hash at height 0 is the txids themself
return vTxid[pos];
} else {
// calculate left hash
uint256 left = CalcHash(height-1, pos*2, vTxid), right;
- // calculate right hash if not beyond the end of the array - copy left hash otherwise1
+ // calculate right hash if not beyond the end of the array - copy left hash otherwise
if (pos*2+1 < CalcTreeWidth(height-1))
right = CalcHash(height-1, pos*2+1, vTxid);
else
@@ -155,7 +135,7 @@ uint256 CPartialMerkleTree::ExtractMatches(std::vector<uint256> &vMatch, std::ve
if (nTransactions == 0)
return uint256();
// check for excessively high numbers of transactions
- if (nTransactions > MAX_BLOCK_BASE_SIZE / 60) // 60 is the lower bound for the size of a serialized CTransaction
+ if (nTransactions > MAX_BLOCK_WEIGHT / MIN_TRANSACTION_WEIGHT)
return uint256();
// there can never be more hashes provided than one for every txid
if (vHash.size() > nTransactions)
diff --git a/src/merkleblock.h b/src/merkleblock.h
index 73cbf670ee..6c05f2c1f8 100644
--- a/src/merkleblock.h
+++ b/src/merkleblock.h
@@ -23,7 +23,7 @@
* storing a bit for each traversed node, signifying whether the node is the
* parent of at least one matched leaf txid (or a matched txid itself). In
* case we are at the leaf level, or this bit is 0, its merkle node hash is
- * stored, and its children are not explorer further. Otherwise, no hash is
+ * stored, and its children are not explored further. Otherwise, no hash is
* stored, but we recurse into both (or the only) child branch. During
* decoding, the same depth-first traversal is performed, consuming bits and
* hashes as they written during encoding.
@@ -63,7 +63,7 @@ protected:
bool fBad;
/** helper function to efficiently calculate the number of nodes at given height in the merkle tree */
- unsigned int CalcTreeWidth(int height) {
+ unsigned int CalcTreeWidth(int height) const {
return (nTransactions+(1 << height)-1) >> height;
}
@@ -121,6 +121,8 @@ public:
/**
* Used to relay blocks as header + vector<merkle branch>
* to filtered nodes.
+ *
+ * NOTE: The class assumes that the given CBlock has *at least* 1 transaction. If the CBlock has 0 txs, it will hit an assertion.
*/
class CMerkleBlock
{
@@ -129,8 +131,12 @@ public:
CBlockHeader header;
CPartialMerkleTree txn;
-public:
- /** Public only for unit testing and relay testing (not relayed) */
+ /**
+ * Public only for unit testing and relay testing (not relayed).
+ *
+ * Used only when a bloom filter is specified to allow
+ * testing the transactions which matched the bloom filter.
+ */
std::vector<std::pair<unsigned int, uint256> > vMatchedTxn;
/**
@@ -138,10 +144,10 @@ public:
* Note that this will call IsRelevantAndUpdate on the filter for each transaction,
* thus the filter will likely be modified.
*/
- CMerkleBlock(const CBlock& block, CBloomFilter& filter);
+ CMerkleBlock(const CBlock& block, CBloomFilter& filter) : CMerkleBlock(block, &filter, nullptr) { }
// Create from a CBlock, matching the txids in the set
- CMerkleBlock(const CBlock& block, const std::set<uint256>& txids);
+ CMerkleBlock(const CBlock& block, const std::set<uint256>& txids) : CMerkleBlock(block, nullptr, &txids) { }
CMerkleBlock() {}
@@ -152,6 +158,10 @@ public:
READWRITE(header);
READWRITE(txn);
}
+
+private:
+ // Combined constructor to consolidate code
+ CMerkleBlock(const CBlock& block, CBloomFilter* filter, const std::set<uint256>* txids);
};
#endif // BITCOIN_MERKLEBLOCK_H
diff --git a/src/miner.cpp b/src/miner.cpp
index acded94168..a9989f4b17 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -10,11 +10,13 @@
#include "chainparams.h"
#include "coins.h"
#include "consensus/consensus.h"
+#include "consensus/tx_verify.h"
#include "consensus/merkle.h"
#include "consensus/validation.h"
#include "hash.h"
#include "validation.h"
#include "net.h"
+#include "policy/feerate.h"
#include "policy/policy.h"
#include "pow.h"
#include "primitives/transaction.h"
@@ -26,13 +28,9 @@
#include "validationinterface.h"
#include <algorithm>
-#include <boost/thread.hpp>
-#include <boost/tuple/tuple.hpp>
#include <queue>
#include <utility>
-using namespace std;
-
//////////////////////////////////////////////////////////////////////////////
//
// BitcoinMiner
@@ -41,24 +39,12 @@ using namespace std;
//
// Unconfirmed transactions in the memory pool often depend on other
// transactions in the memory pool. When we select transactions from the
-// pool, we select by highest priority or fee rate, so we might consider
-// transactions that depend on transactions that aren't yet in the block.
+// pool, we select by highest fee rate of a transaction combined with all
+// its ancestors.
uint64_t nLastBlockTx = 0;
-uint64_t nLastBlockSize = 0;
uint64_t nLastBlockWeight = 0;
-class ScoreCompare
-{
-public:
- ScoreCompare() {}
-
- bool operator()(const CTxMemPool::txiter a, const CTxMemPool::txiter b)
- {
- return CompareTxMemPoolEntryByScore()(*b,*a); // Convert to less than
- }
-};
-
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
{
int64_t nOldTime = pblock->nTime;
@@ -74,49 +60,43 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam
return nNewTime - nOldTime;
}
-BlockAssembler::BlockAssembler(const CChainParams& _chainparams)
- : chainparams(_chainparams)
+BlockAssembler::Options::Options() {
+ blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
+ nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT;
+}
+
+BlockAssembler::BlockAssembler(const CChainParams& params, const Options& options) : chainparams(params)
+{
+ blockMinFeeRate = options.blockMinFeeRate;
+ // Limit weight to between 4K and MAX_BLOCK_WEIGHT-4K for sanity:
+ nBlockMaxWeight = std::max<size_t>(4000, std::min<size_t>(MAX_BLOCK_WEIGHT - 4000, options.nBlockMaxWeight));
+}
+
+static BlockAssembler::Options DefaultOptions(const CChainParams& params)
{
// Block resource limits
// If neither -blockmaxsize or -blockmaxweight is given, limit to DEFAULT_BLOCK_MAX_*
// If only one is given, only restrict the specified resource.
// If both are given, restrict both.
- nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT;
- nBlockMaxSize = DEFAULT_BLOCK_MAX_SIZE;
- bool fWeightSet = false;
- if (IsArgSet("-blockmaxweight")) {
- nBlockMaxWeight = GetArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT);
- nBlockMaxSize = MAX_BLOCK_SERIALIZED_SIZE;
- fWeightSet = true;
- }
- if (IsArgSet("-blockmaxsize")) {
- nBlockMaxSize = GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE);
- if (!fWeightSet) {
- nBlockMaxWeight = nBlockMaxSize * WITNESS_SCALE_FACTOR;
- }
- }
- if (IsArgSet("-blockmintxfee")) {
+ BlockAssembler::Options options;
+ options.nBlockMaxWeight = gArgs.GetArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT);
+ if (gArgs.IsArgSet("-blockmintxfee")) {
CAmount n = 0;
- ParseMoney(GetArg("-blockmintxfee", ""), n);
- blockMinFeeRate = CFeeRate(n);
+ ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n);
+ options.blockMinFeeRate = CFeeRate(n);
} else {
- blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
+ options.blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
}
-
- // Limit weight to between 4K and MAX_BLOCK_WEIGHT-4K for sanity:
- nBlockMaxWeight = std::max((unsigned int)4000, std::min((unsigned int)(MAX_BLOCK_WEIGHT-4000), nBlockMaxWeight));
- // Limit size to between 1K and MAX_BLOCK_SERIALIZED_SIZE-1K for sanity:
- nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SERIALIZED_SIZE-1000), nBlockMaxSize));
- // Whether we need to account for byte usage (in addition to weight usage)
- fNeedSizeAccounting = (nBlockMaxSize < MAX_BLOCK_SERIALIZED_SIZE-1000);
+ return options;
}
+BlockAssembler::BlockAssembler(const CChainParams& params) : BlockAssembler(params, DefaultOptions(params)) {}
+
void BlockAssembler::resetBlock()
{
inBlock.clear();
// Reserve space for coinbase tx
- nBlockSize = 1000;
nBlockWeight = 4000;
nBlockSigOpsCost = 400;
fIncludeWitness = false;
@@ -124,13 +104,12 @@ void BlockAssembler::resetBlock()
// These counters do not include coinbase tx
nBlockTx = 0;
nFees = 0;
-
- lastFewTxs = 0;
- blockFinished = false;
}
-std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
+std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx)
{
+ int64_t nTimeStart = GetTimeMicros();
+
resetBlock();
pblocktemplate.reset(new CBlockTemplate());
@@ -146,13 +125,14 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
LOCK2(cs_main, mempool.cs);
CBlockIndex* pindexPrev = chainActive.Tip();
+ assert(pindexPrev != nullptr);
nHeight = pindexPrev->nHeight + 1;
pblock->nVersion = ComputeBlockVersion(pindexPrev, chainparams.GetConsensus());
// -regtest only: allow overriding block.nVersion with
// -blockversion=N to test forking scenarios
if (chainparams.MineBlocksOnDemand())
- pblock->nVersion = GetArg("-blockversion", pblock->nVersion);
+ pblock->nVersion = gArgs.GetArg("-blockversion", pblock->nVersion);
pblock->nTime = GetAdjustedTime();
const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast();
@@ -167,13 +147,15 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
// -promiscuousmempoolflags is used.
// TODO: replace this with a call to main to assess validity of a mempool
// transaction (which in most cases can be a no-op).
- fIncludeWitness = IsWitnessEnabled(pindexPrev, chainparams.GetConsensus());
+ fIncludeWitness = IsWitnessEnabled(pindexPrev, chainparams.GetConsensus()) && fMineWitnessTx;
+
+ int nPackagesSelected = 0;
+ int nDescendantsUpdated = 0;
+ addPackageTxs(nPackagesSelected, nDescendantsUpdated);
- addPriorityTxs();
- addPackageTxs();
+ int64_t nTime1 = GetTimeMicros();
nLastBlockTx = nBlockTx;
- nLastBlockSize = nBlockSize;
nLastBlockWeight = nBlockWeight;
// Create coinbase transaction.
@@ -188,8 +170,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
pblocktemplate->vchCoinbaseCommitment = GenerateCoinbaseCommitment(*pblock, pindexPrev, chainparams.GetConsensus());
pblocktemplate->vTxFees[0] = -nFees;
- uint64_t nSerializeSize = GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION);
- LogPrintf("CreateNewBlock(): total size: %u block weight: %u txs: %u fees: %ld sigops %d\n", nSerializeSize, GetBlockWeight(*pblock), nBlockTx, nFees, nBlockSigOpsCost);
+ LogPrintf("CreateNewBlock(): block weight: %u txs: %u fees: %ld sigops %d\n", GetBlockWeight(*pblock), nBlockTx, nFees, nBlockSigOpsCost);
// Fill in header
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
@@ -202,19 +183,11 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) {
throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state)));
}
+ int64_t nTime2 = GetTimeMicros();
- return std::move(pblocktemplate);
-}
+ LogPrint(BCLog::BENCH, "CreateNewBlock() packages: %.2fms (%d packages, %d updated descendants), validity: %.2fms (total %.2fms)\n", 0.001 * (nTime1 - nTimeStart), nPackagesSelected, nDescendantsUpdated, 0.001 * (nTime2 - nTime1), 0.001 * (nTime2 - nTimeStart));
-bool BlockAssembler::isStillDependent(CTxMemPool::txiter iter)
-{
- BOOST_FOREACH(CTxMemPool::txiter parent, mempool.GetMemPoolParents(iter))
- {
- if (!inBlock.count(parent)) {
- return true;
- }
- }
- return false;
+ return std::move(pblocktemplate);
}
void BlockAssembler::onlyUnconfirmed(CTxMemPool::setEntries& testSet)
@@ -230,7 +203,7 @@ void BlockAssembler::onlyUnconfirmed(CTxMemPool::setEntries& testSet)
}
}
-bool BlockAssembler::TestPackage(uint64_t packageSize, int64_t packageSigOpsCost)
+bool BlockAssembler::TestPackage(uint64_t packageSize, int64_t packageSigOpsCost) const
{
// TODO: switch to weight-based accounting for packages instead of vsize-based accounting.
if (nBlockWeight + WITNESS_SCALE_FACTOR * packageSize >= nBlockMaxWeight)
@@ -244,75 +217,14 @@ bool BlockAssembler::TestPackage(uint64_t packageSize, int64_t packageSigOpsCost
// - transaction finality (locktime)
// - premature witness (in case segwit transactions are added to mempool before
// segwit activation)
-// - serialized size (in case -blockmaxsize is in use)
bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& package)
{
- uint64_t nPotentialBlockSize = nBlockSize; // only used with fNeedSizeAccounting
- BOOST_FOREACH (const CTxMemPool::txiter it, package) {
+ for (const CTxMemPool::txiter it : package) {
if (!IsFinalTx(it->GetTx(), nHeight, nLockTimeCutoff))
return false;
if (!fIncludeWitness && it->GetTx().HasWitness())
return false;
- if (fNeedSizeAccounting) {
- uint64_t nTxSize = ::GetSerializeSize(it->GetTx(), SER_NETWORK, PROTOCOL_VERSION);
- if (nPotentialBlockSize + nTxSize >= nBlockMaxSize) {
- return false;
- }
- nPotentialBlockSize += nTxSize;
- }
- }
- return true;
-}
-
-bool BlockAssembler::TestForBlock(CTxMemPool::txiter iter)
-{
- if (nBlockWeight + iter->GetTxWeight() >= nBlockMaxWeight) {
- // If the block is so close to full that no more txs will fit
- // or if we've tried more than 50 times to fill remaining space
- // then flag that the block is finished
- if (nBlockWeight > nBlockMaxWeight - 400 || lastFewTxs > 50) {
- blockFinished = true;
- return false;
- }
- // Once we're within 4000 weight of a full block, only look at 50 more txs
- // to try to fill the remaining space.
- if (nBlockWeight > nBlockMaxWeight - 4000) {
- lastFewTxs++;
- }
- return false;
- }
-
- if (fNeedSizeAccounting) {
- if (nBlockSize + ::GetSerializeSize(iter->GetTx(), SER_NETWORK, PROTOCOL_VERSION) >= nBlockMaxSize) {
- if (nBlockSize > nBlockMaxSize - 100 || lastFewTxs > 50) {
- blockFinished = true;
- return false;
- }
- if (nBlockSize > nBlockMaxSize - 1000) {
- lastFewTxs++;
- }
- return false;
- }
- }
-
- if (nBlockSigOpsCost + iter->GetSigOpCost() >= MAX_BLOCK_SIGOPS_COST) {
- // If the block has room for no more sig ops then
- // flag that the block is finished
- if (nBlockSigOpsCost > MAX_BLOCK_SIGOPS_COST - 8) {
- blockFinished = true;
- return false;
- }
- // Otherwise attempt to find another tx with fewer sigops
- // to put in the block.
- return false;
}
-
- // Must check that lock times are still valid
- // This can be removed once MTP is always enforced
- // as long as reorgs keep the mempool consistent.
- if (!IsFinalTx(iter->GetTx(), nHeight, nLockTimeCutoff))
- return false;
-
return true;
}
@@ -321,37 +233,32 @@ void BlockAssembler::AddToBlock(CTxMemPool::txiter iter)
pblock->vtx.emplace_back(iter->GetSharedTx());
pblocktemplate->vTxFees.push_back(iter->GetFee());
pblocktemplate->vTxSigOpsCost.push_back(iter->GetSigOpCost());
- if (fNeedSizeAccounting) {
- nBlockSize += ::GetSerializeSize(iter->GetTx(), SER_NETWORK, PROTOCOL_VERSION);
- }
nBlockWeight += iter->GetTxWeight();
++nBlockTx;
nBlockSigOpsCost += iter->GetSigOpCost();
nFees += iter->GetFee();
inBlock.insert(iter);
- bool fPrintPriority = GetBoolArg("-printpriority", DEFAULT_PRINTPRIORITY);
+ bool fPrintPriority = gArgs.GetBoolArg("-printpriority", DEFAULT_PRINTPRIORITY);
if (fPrintPriority) {
- double dPriority = iter->GetPriority(nHeight);
- CAmount dummy;
- mempool.ApplyDeltas(iter->GetTx().GetHash(), dPriority, dummy);
- LogPrintf("priority %.1f fee %s txid %s\n",
- dPriority,
+ LogPrintf("fee %s txid %s\n",
CFeeRate(iter->GetModifiedFee(), iter->GetTxSize()).ToString(),
iter->GetTx().GetHash().ToString());
}
}
-void BlockAssembler::UpdatePackagesForAdded(const CTxMemPool::setEntries& alreadyAdded,
+int BlockAssembler::UpdatePackagesForAdded(const CTxMemPool::setEntries& alreadyAdded,
indexed_modified_transaction_set &mapModifiedTx)
{
- BOOST_FOREACH(const CTxMemPool::txiter it, alreadyAdded) {
+ int nDescendantsUpdated = 0;
+ for (const CTxMemPool::txiter it : alreadyAdded) {
CTxMemPool::setEntries descendants;
mempool.CalculateDescendants(it, descendants);
// Insert all descendants (not yet in block) into the modified set
- BOOST_FOREACH(CTxMemPool::txiter desc, descendants) {
+ for (CTxMemPool::txiter desc : descendants) {
if (alreadyAdded.count(desc))
continue;
+ ++nDescendantsUpdated;
modtxiter mit = mapModifiedTx.find(desc);
if (mit == mapModifiedTx.end()) {
CTxMemPoolModifiedEntry modEntry(desc);
@@ -364,6 +271,7 @@ void BlockAssembler::UpdatePackagesForAdded(const CTxMemPool::setEntries& alread
}
}
}
+ return nDescendantsUpdated;
}
// Skip entries in mapTx that are already in a block or are present
@@ -378,9 +286,7 @@ void BlockAssembler::UpdatePackagesForAdded(const CTxMemPool::setEntries& alread
bool BlockAssembler::SkipMapTxEntry(CTxMemPool::txiter it, indexed_modified_transaction_set &mapModifiedTx, CTxMemPool::setEntries &failedTx)
{
assert (it != mempool.mapTx.end());
- if (mapModifiedTx.count(it) || inBlock.count(it) || failedTx.count(it))
- return true;
- return false;
+ return mapModifiedTx.count(it) || inBlock.count(it) || failedTx.count(it);
}
void BlockAssembler::SortForBlock(const CTxMemPool::setEntries& package, CTxMemPool::txiter entry, std::vector<CTxMemPool::txiter>& sortedEntries)
@@ -404,7 +310,7 @@ void BlockAssembler::SortForBlock(const CTxMemPool::setEntries& package, CTxMemP
// Each time through the loop, we compare the best transaction in
// mapModifiedTxs with the next transaction in the mempool to decide what
// transaction package to work on next.
-void BlockAssembler::addPackageTxs()
+void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated)
{
// mapModifiedTx will store sorted packages after they are modified
// because some of their txs are already in the block
@@ -418,6 +324,13 @@ void BlockAssembler::addPackageTxs()
CTxMemPool::indexed_transaction_set::index<ancestor_score>::type::iterator mi = mempool.mapTx.get<ancestor_score>().begin();
CTxMemPool::txiter iter;
+
+ // Limit the number of attempts to add transactions to the block when it is
+ // close to full; this is just a simple heuristic to finish quickly if the
+ // mempool has a lot of entries.
+ const int64_t MAX_CONSECUTIVE_FAILURES = 1000;
+ int64_t nConsecutiveFailed = 0;
+
while (mi != mempool.mapTx.get<ancestor_score>().end() || !mapModifiedTx.empty())
{
// First try to find a new transaction in mapTx to evaluate.
@@ -479,6 +392,14 @@ void BlockAssembler::addPackageTxs()
mapModifiedTx.get<ancestor_score>().erase(modit);
failedTx.insert(iter);
}
+
+ ++nConsecutiveFailed;
+
+ if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES && nBlockWeight >
+ nBlockMaxWeight - 4000) {
+ // Give up if we're close to full and haven't succeeded in a while
+ break;
+ }
continue;
}
@@ -499,8 +420,11 @@ void BlockAssembler::addPackageTxs()
continue;
}
+ // This transaction will make it in; reset the failed counter.
+ nConsecutiveFailed = 0;
+
// Package can be added. Sort the entries in a valid order.
- vector<CTxMemPool::txiter> sortedEntries;
+ std::vector<CTxMemPool::txiter> sortedEntries;
SortForBlock(ancestors, iter, sortedEntries);
for (size_t i=0; i<sortedEntries.size(); ++i) {
@@ -509,91 +433,11 @@ void BlockAssembler::addPackageTxs()
mapModifiedTx.erase(sortedEntries[i]);
}
- // Update transactions that depend on each of these
- UpdatePackagesForAdded(ancestors, mapModifiedTx);
- }
-}
+ ++nPackagesSelected;
-void BlockAssembler::addPriorityTxs()
-{
- // How much of the block should be dedicated to high-priority transactions,
- // included regardless of the fees they pay
- unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", DEFAULT_BLOCK_PRIORITY_SIZE);
- nBlockPrioritySize = std::min(nBlockMaxSize, nBlockPrioritySize);
-
- if (nBlockPrioritySize == 0) {
- return;
- }
-
- bool fSizeAccounting = fNeedSizeAccounting;
- fNeedSizeAccounting = true;
-
- // This vector will be sorted into a priority queue:
- vector<TxCoinAgePriority> vecPriority;
- TxCoinAgePriorityCompare pricomparer;
- std::map<CTxMemPool::txiter, double, CTxMemPool::CompareIteratorByHash> waitPriMap;
- typedef std::map<CTxMemPool::txiter, double, CTxMemPool::CompareIteratorByHash>::iterator waitPriIter;
- double actualPriority = -1;
-
- vecPriority.reserve(mempool.mapTx.size());
- for (CTxMemPool::indexed_transaction_set::iterator mi = mempool.mapTx.begin();
- mi != mempool.mapTx.end(); ++mi)
- {
- double dPriority = mi->GetPriority(nHeight);
- CAmount dummy;
- mempool.ApplyDeltas(mi->GetTx().GetHash(), dPriority, dummy);
- vecPriority.push_back(TxCoinAgePriority(dPriority, mi));
- }
- std::make_heap(vecPriority.begin(), vecPriority.end(), pricomparer);
-
- CTxMemPool::txiter iter;
- while (!vecPriority.empty() && !blockFinished) { // add a tx from priority queue to fill the blockprioritysize
- iter = vecPriority.front().second;
- actualPriority = vecPriority.front().first;
- std::pop_heap(vecPriority.begin(), vecPriority.end(), pricomparer);
- vecPriority.pop_back();
-
- // If tx already in block, skip
- if (inBlock.count(iter)) {
- assert(false); // shouldn't happen for priority txs
- continue;
- }
-
- // cannot accept witness transactions into a non-witness block
- if (!fIncludeWitness && iter->GetTx().HasWitness())
- continue;
-
- // If tx is dependent on other mempool txs which haven't yet been included
- // then put it in the waitSet
- if (isStillDependent(iter)) {
- waitPriMap.insert(std::make_pair(iter, actualPriority));
- continue;
- }
-
- // If this tx fits in the block add it, otherwise keep looping
- if (TestForBlock(iter)) {
- AddToBlock(iter);
-
- // If now that this txs is added we've surpassed our desired priority size
- // or have dropped below the AllowFreeThreshold, then we're done adding priority txs
- if (nBlockSize >= nBlockPrioritySize || !AllowFree(actualPriority)) {
- break;
- }
-
- // This tx was successfully added, so
- // add transactions that depend on this one to the priority queue to try again
- BOOST_FOREACH(CTxMemPool::txiter child, mempool.GetMemPoolChildren(iter))
- {
- waitPriIter wpiter = waitPriMap.find(child);
- if (wpiter != waitPriMap.end()) {
- vecPriority.push_back(TxCoinAgePriority(wpiter->second,child));
- std::push_heap(vecPriority.begin(), vecPriority.end(), pricomparer);
- waitPriMap.erase(wpiter);
- }
- }
- }
+ // Update transactions that depend on each of these
+ nDescendantsUpdated += UpdatePackagesForAdded(ancestors, mapModifiedTx);
}
- fNeedSizeAccounting = fSizeAccounting;
}
void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce)
diff --git a/src/miner.h b/src/miner.h
index 3ba92b16b8..db165e71c6 100644
--- a/src/miner.h
+++ b/src/miner.h
@@ -11,14 +11,12 @@
#include <stdint.h>
#include <memory>
-#include "boost/multi_index_container.hpp"
-#include "boost/multi_index/ordered_index.hpp"
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/ordered_index.hpp>
class CBlockIndex;
class CChainParams;
-class CReserveKey;
class CScript;
-class CWallet;
namespace Consensus { struct Params; };
@@ -35,7 +33,7 @@ struct CBlockTemplate
// Container for tracking updates to ancestor feerate as we include (parent)
// transactions in a block
struct CTxMemPoolModifiedEntry {
- CTxMemPoolModifiedEntry(CTxMemPool::txiter entry)
+ explicit CTxMemPoolModifiedEntry(CTxMemPool::txiter entry)
{
iter = entry;
nSizeWithAncestors = entry->GetSizeWithAncestors();
@@ -118,7 +116,7 @@ typedef indexed_modified_transaction_set::index<ancestor_score>::type::iterator
struct update_for_parent_inclusion
{
- update_for_parent_inclusion(CTxMemPool::txiter it) : iter(it) {}
+ explicit update_for_parent_inclusion(CTxMemPool::txiter it) : iter(it) {}
void operator() (CTxMemPoolModifiedEntry &e)
{
@@ -141,13 +139,11 @@ private:
// Configuration parameters for the block size
bool fIncludeWitness;
- unsigned int nBlockMaxWeight, nBlockMaxSize;
- bool fNeedSizeAccounting;
+ unsigned int nBlockMaxWeight;
CFeeRate blockMinFeeRate;
// Information on the current status of the block
uint64_t nBlockWeight;
- uint64_t nBlockSize;
uint64_t nBlockTx;
uint64_t nBlockSigOpsCost;
CAmount nFees;
@@ -158,14 +154,18 @@ private:
int64_t nLockTimeCutoff;
const CChainParams& chainparams;
- // Variables used for addPriorityTxs
- int lastFewTxs;
- bool blockFinished;
-
public:
- BlockAssembler(const CChainParams& chainparams);
+ struct Options {
+ Options();
+ size_t nBlockMaxWeight;
+ CFeeRate blockMinFeeRate;
+ };
+
+ explicit BlockAssembler(const CChainParams& params);
+ BlockAssembler(const CChainParams& params, const Options& options);
+
/** Construct a new block template with coinbase to scriptPubKeyIn */
- std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn);
+ std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx=true);
private:
// utility functions
@@ -175,22 +175,16 @@ private:
void AddToBlock(CTxMemPool::txiter iter);
// Methods for how to add transactions to a block.
- /** Add transactions based on tx "priority" */
- void addPriorityTxs();
- /** Add transactions based on feerate including unconfirmed ancestors */
- void addPackageTxs();
-
- // helper function for addPriorityTxs
- /** Test if tx will still "fit" in the block */
- bool TestForBlock(CTxMemPool::txiter iter);
- /** Test if tx still has unconfirmed parents not yet in block */
- bool isStillDependent(CTxMemPool::txiter iter);
+ /** Add transactions based on feerate including unconfirmed ancestors
+ * Increments nPackagesSelected / nDescendantsUpdated with corresponding
+ * statistics from the package selection (for logging statistics). */
+ void addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated);
// helper functions for addPackageTxs()
/** Remove confirmed (inBlock) entries from given set */
void onlyUnconfirmed(CTxMemPool::setEntries& testSet);
/** Test if a new package would "fit" in the block */
- bool TestPackage(uint64_t packageSize, int64_t packageSigOpsCost);
+ bool TestPackage(uint64_t packageSize, int64_t packageSigOpsCost) const;
/** Perform checks on each transaction in a package:
* locktime, premature-witness, serialized size (if necessary)
* These checks should always succeed, and they're here
@@ -202,8 +196,9 @@ private:
/** Sort the package in an order that is valid to appear in a block */
void SortForBlock(const CTxMemPool::setEntries& package, CTxMemPool::txiter entry, std::vector<CTxMemPool::txiter>& sortedEntries);
/** Add descendants of given transactions to mapModifiedTx with ancestor
- * state updated assuming given transactions are inBlock. */
- void UpdatePackagesForAdded(const CTxMemPool::setEntries& alreadyAdded, indexed_modified_transaction_set &mapModifiedTx);
+ * state updated assuming given transactions are inBlock. Returns number
+ * of updated descendants. */
+ int UpdatePackagesForAdded(const CTxMemPool::setEntries& alreadyAdded, indexed_modified_transaction_set &mapModifiedTx);
};
/** Modify the extranonce in a block */
diff --git a/src/net.cpp b/src/net.cpp
index b275bdd809..ea3840a708 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -44,10 +44,15 @@
// We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization.
#define FEELER_SLEEP_WINDOW 1
-#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
+#if !defined(HAVE_MSG_NOSIGNAL)
#define MSG_NOSIGNAL 0
#endif
+// MSG_DONTWAIT is not available on some platforms, if it doesn't exist define it as 0
+#if !defined(HAVE_MSG_DONTWAIT)
+#define MSG_DONTWAIT 0
+#endif
+
// Fix for ancient MinGW versions, that don't have defined these in ws2tcpip.h.
// Todo: Can be removed when our pull-tester is upgraded to a modern MinGW version.
#ifdef WIN32
@@ -59,6 +64,14 @@
#endif
#endif
+/** Used to pass flags to the Bind() function */
+enum BindFlags {
+ BF_NONE = 0,
+ BF_EXPLICIT = (1U << 0),
+ BF_REPORT_ERROR = (1U << 1),
+ BF_WHITELIST = (1U << 2),
+};
+
const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*";
static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8]
@@ -76,10 +89,6 @@ std::string strSubVersion;
limitedmap<uint256, int64_t> mapAlreadyAskedFor(MAX_INV_SZ);
-// Signals for message handling
-static CNodeSignals g_signals;
-CNodeSignals& GetNodeSignals() { return g_signals; }
-
void CConnman::AddOneShot(const std::string& strDest)
{
LOCK(cs_vOneShots);
@@ -88,7 +97,7 @@ void CConnman::AddOneShot(const std::string& strDest)
unsigned short GetListenPort()
{
- return (unsigned short)(GetArg("-port", Params().GetDefaultPort()));
+ return (unsigned short)(gArgs.GetArg("-port", Params().GetDefaultPort()));
}
// find 'best' local address for a particular peer
@@ -126,11 +135,10 @@ static std::vector<CAddress> convertSeed6(const std::vector<SeedSpec6> &vSeedsIn
const int64_t nOneWeek = 7*24*60*60;
std::vector<CAddress> vSeedsOut;
vSeedsOut.reserve(vSeedsIn.size());
- for (std::vector<SeedSpec6>::const_iterator i(vSeedsIn.begin()); i != vSeedsIn.end(); ++i)
- {
+ for (const auto& seed_in : vSeedsIn) {
struct in6_addr ip;
- memcpy(&ip, i->addr, sizeof(ip));
- CAddress addr(CService(ip, i->port), NODE_NETWORK);
+ memcpy(&ip, seed_in.addr, sizeof(ip));
+ CAddress addr(CService(ip, seed_in.port), NODE_NETWORK);
addr.nTime = GetTime() - GetRand(nOneWeek) - nOneWeek;
vSeedsOut.push_back(addr);
}
@@ -143,7 +151,7 @@ static std::vector<CAddress> convertSeed6(const std::vector<SeedSpec6> &vSeedsIn
// one by discovery.
CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices)
{
- CAddress ret(CService(CNetAddr(),GetListenPort()), NODE_NONE);
+ CAddress ret(CService(CNetAddr(),GetListenPort()), nLocalServices);
CService addr;
if (GetLocal(addr, paddrPeer))
{
@@ -164,8 +172,9 @@ int GetnScore(const CService& addr)
// Is our peer's addrLocal potentially useful as an external IP source?
bool IsPeerAddrLocalGood(CNode *pnode)
{
- return fDiscover && pnode->addr.IsRoutable() && pnode->addrLocal.IsRoutable() &&
- !IsLimited(pnode->addrLocal.GetNetwork());
+ CService addrLocal = pnode->GetAddrLocal();
+ return fDiscover && pnode->addr.IsRoutable() && addrLocal.IsRoutable() &&
+ !IsLimited(addrLocal.GetNetwork());
}
// pushes our own address to a peer
@@ -180,11 +189,11 @@ void AdvertiseLocal(CNode *pnode)
if (IsPeerAddrLocalGood(pnode) && (!addrLocal.IsRoutable() ||
GetRand((GetnScore(addrLocal) > LOCAL_MANUAL) ? 8:2) == 0))
{
- addrLocal.SetIP(pnode->addrLocal);
+ addrLocal.SetIP(pnode->GetAddrLocal());
}
if (addrLocal.IsRoutable())
{
- LogPrint("net", "AdvertiseLocal: advertising address %s\n", addrLocal.ToString());
+ LogPrint(BCLog::NET, "AdvertiseLocal: advertising address %s\n", addrLocal.ToString());
FastRandomContext insecure_rand;
pnode->PushAddress(addrLocal, insecure_rand);
}
@@ -234,7 +243,7 @@ bool RemoveLocal(const CService& addr)
/** Make a particular network entirely off-limits (no automatic connects to it) */
void SetLimited(enum Network net, bool fLimited)
{
- if (net == NET_UNROUTABLE)
+ if (net == NET_UNROUTABLE || net == NET_INTERNAL)
return;
LOCK(cs_mapLocalHost);
vfLimited[net] = fLimited;
@@ -289,124 +298,159 @@ bool IsReachable(const CNetAddr& addr)
CNode* CConnman::FindNode(const CNetAddr& ip)
{
LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
- if ((CNetAddr)pnode->addr == ip)
- return (pnode);
- return NULL;
+ for (CNode* pnode : vNodes) {
+ if ((CNetAddr)pnode->addr == ip) {
+ return pnode;
+ }
+ }
+ return nullptr;
}
CNode* CConnman::FindNode(const CSubNet& subNet)
{
LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (subNet.Match((CNetAddr)pnode->addr))
- return (pnode);
- return NULL;
+ for (CNode* pnode : vNodes) {
+ if (subNet.Match((CNetAddr)pnode->addr)) {
+ return pnode;
+ }
+ }
+ return nullptr;
}
CNode* CConnman::FindNode(const std::string& addrName)
{
LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (pnode->addrName == addrName)
- return (pnode);
- return NULL;
+ for (CNode* pnode : vNodes) {
+ if (pnode->GetAddrName() == addrName) {
+ return pnode;
+ }
+ }
+ return nullptr;
}
CNode* CConnman::FindNode(const CService& addr)
{
LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
- if ((CService)pnode->addr == addr)
- return (pnode);
- return NULL;
+ for (CNode* pnode : vNodes) {
+ if ((CService)pnode->addr == addr) {
+ return pnode;
+ }
+ }
+ return nullptr;
}
bool CConnman::CheckIncomingNonce(uint64_t nonce)
{
LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes) {
+ for (CNode* pnode : vNodes) {
if (!pnode->fSuccessfullyConnected && !pnode->fInbound && pnode->GetLocalNonce() == nonce)
return false;
}
return true;
}
+/** Get the bind address for a socket as CAddress */
+static CAddress GetBindAddress(SOCKET sock)
+{
+ CAddress addr_bind;
+ struct sockaddr_storage sockaddr_bind;
+ socklen_t sockaddr_bind_len = sizeof(sockaddr_bind);
+ if (sock != INVALID_SOCKET) {
+ if (!getsockname(sock, (struct sockaddr*)&sockaddr_bind, &sockaddr_bind_len)) {
+ addr_bind.SetSockAddr((const struct sockaddr*)&sockaddr_bind);
+ } else {
+ LogPrint(BCLog::NET, "Warning: getsockname failed\n");
+ }
+ }
+ return addr_bind;
+}
+
CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure)
{
- if (pszDest == NULL) {
+ if (pszDest == nullptr) {
if (IsLocal(addrConnect))
- return NULL;
+ return nullptr;
// Look for an existing connection
CNode* pnode = FindNode((CService)addrConnect);
if (pnode)
{
- pnode->AddRef();
- return pnode;
+ LogPrintf("Failed to open new connection, already connected\n");
+ return nullptr;
}
}
/// debug print
- LogPrint("net", "trying connection %s lastseen=%.1fhrs\n",
+ LogPrint(BCLog::NET, "trying connection %s lastseen=%.1fhrs\n",
pszDest ? pszDest : addrConnect.ToString(),
pszDest ? 0.0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0);
- // Connect
- SOCKET hSocket;
- bool proxyConnectionFailed = false;
- 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;
- }
-
- if (pszDest && addrConnect.IsValid()) {
+ // Resolve
+ const int default_port = Params().GetDefaultPort();
+ if (pszDest) {
+ std::vector<CService> resolved;
+ if (Lookup(pszDest, resolved, default_port, fNameLookup && !HaveNameProxy(), 256) && !resolved.empty()) {
+ addrConnect = CAddress(resolved[GetRand(resolved.size())], NODE_NONE);
+ if (!addrConnect.IsValid()) {
+ LogPrint(BCLog::NET, "Resolver returned invalid address %s for %s", addrConnect.ToString(), pszDest);
+ return nullptr;
+ }
// It is possible that we already have a connection to the IP/port pszDest resolved to.
// In that case, drop the connection that was just created, and return the existing CNode instead.
// Also store the name we used to connect in that CNode, so that future FindNode() calls to that
// name catch this early.
+ LOCK(cs_vNodes);
CNode* pnode = FindNode((CService)addrConnect);
if (pnode)
{
- pnode->AddRef();
- {
- LOCK(cs_vNodes);
- if (pnode->addrName.empty()) {
- pnode->addrName = std::string(pszDest);
- }
- }
- CloseSocket(hSocket);
- return pnode;
+ pnode->MaybeSetAddrName(std::string(pszDest));
+ LogPrintf("Failed to open new connection, already connected\n");
+ return nullptr;
}
}
+ }
- addrman.Attempt(addrConnect, fCountFailure);
+ // Connect
+ bool connected = false;
+ SOCKET hSocket;
+ proxyType proxy;
+ if (addrConnect.IsValid()) {
+ bool proxyConnectionFailed = false;
+
+ if (GetProxy(addrConnect.GetNetwork(), proxy))
+ connected = ConnectThroughProxy(proxy, addrConnect.ToStringIP(), addrConnect.GetPort(), hSocket, nConnectTimeout, &proxyConnectionFailed);
+ else // no proxy needed (none set for target network)
+ connected = ConnectSocketDirectly(addrConnect, hSocket, nConnectTimeout);
+ if (!proxyConnectionFailed) {
+ // If a connection to the node was attempted, and failure (if any) is not caused by a problem connecting to
+ // the proxy, mark this as an attempt.
+ addrman.Attempt(addrConnect, fCountFailure);
+ }
+ } else if (pszDest && GetNameProxy(proxy)) {
+ std::string host;
+ int port = default_port;
+ SplitHostPort(std::string(pszDest), port, host);
+ connected = ConnectThroughProxy(proxy, host, port, hSocket, nConnectTimeout, nullptr);
+ }
+ if (connected) {
+ if (!IsSelectableSocket(hSocket)) {
+ LogPrintf("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n");
+ CloseSocket(hSocket);
+ return nullptr;
+ }
// Add node
NodeId id = GetNewNodeId();
uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
- CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, pszDest ? pszDest : "", false);
+ CAddress addr_bind = GetBindAddress(hSocket);
+ CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, pszDest ? pszDest : "", false);
pnode->nServicesExpected = ServiceFlags(addrConnect.nServices & nRelevantServices);
- pnode->nTimeConnected = GetTime();
pnode->AddRef();
- GetNodeSignals().InitializeNode(pnode, *this);
- {
- LOCK(cs_vNodes);
- vNodes.push_back(pnode);
- }
return pnode;
- } else if (!proxyConnectionFailed) {
- // If connecting to the node failed, and failure is not caused by a problem connecting to
- // the proxy, mark this as an attempt.
- addrman.Attempt(addrConnect, fCountFailure);
}
- return NULL;
+ return nullptr;
}
void CConnman::DumpBanlist()
@@ -420,21 +464,22 @@ void CConnman::DumpBanlist()
CBanDB bandb;
banmap_t banmap;
- SetBannedSetDirty(false);
GetBanned(banmap);
- if (!bandb.Write(banmap))
- SetBannedSetDirty(true);
+ if (bandb.Write(banmap)) {
+ SetBannedSetDirty(false);
+ }
- LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n",
+ LogPrint(BCLog::NET, "Flushed %d banned node ips/subnets to banlist.dat %dms\n",
banmap.size(), GetTimeMillis() - nStart);
}
void CNode::CloseSocketDisconnect()
{
fDisconnect = true;
+ LOCK(cs_hSocket);
if (hSocket != INVALID_SOCKET)
{
- LogPrint("net", "disconnecting peer=%d\n", id);
+ LogPrint(BCLog::NET, "disconnecting peer=%d\n", id);
CloseSocket(hSocket);
}
}
@@ -453,35 +498,30 @@ void CConnman::ClearBanned()
bool CConnman::IsBanned(CNetAddr ip)
{
- bool fResult = false;
- {
- LOCK(cs_setBanned);
- for (banmap_t::iterator it = setBanned.begin(); it != setBanned.end(); it++)
- {
- CSubNet subNet = (*it).first;
- CBanEntry banEntry = (*it).second;
+ LOCK(cs_setBanned);
+ for (const auto& it : setBanned) {
+ CSubNet subNet = it.first;
+ CBanEntry banEntry = it.second;
- if(subNet.Match(ip) && GetTime() < banEntry.nBanUntil)
- fResult = true;
+ if (subNet.Match(ip) && GetTime() < banEntry.nBanUntil) {
+ return true;
}
}
- return fResult;
+ return false;
}
bool CConnman::IsBanned(CSubNet subnet)
{
- bool fResult = false;
+ LOCK(cs_setBanned);
+ banmap_t::iterator i = setBanned.find(subnet);
+ if (i != setBanned.end())
{
- LOCK(cs_setBanned);
- banmap_t::iterator i = setBanned.find(subnet);
- if (i != setBanned.end())
- {
- CBanEntry banEntry = (*i).second;
- if (GetTime() < banEntry.nBanUntil)
- fResult = true;
+ CBanEntry banEntry = (*i).second;
+ if (GetTime() < banEntry.nBanUntil) {
+ return true;
}
}
- return fResult;
+ return false;
}
void CConnman::Ban(const CNetAddr& addr, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) {
@@ -494,7 +534,7 @@ void CConnman::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t ba
banEntry.banReason = banReason;
if (bantimeoffset <= 0)
{
- bantimeoffset = GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME);
+ bantimeoffset = gArgs.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME);
sinceUnixEpoch = false;
}
banEntry.nBanUntil = (sinceUnixEpoch ? 0 : GetTime() )+bantimeoffset;
@@ -512,7 +552,7 @@ void CConnman::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t ba
clientInterface->BannedListChanged();
{
LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes) {
+ for (CNode* pnode : vNodes) {
if (subNet.Match((CNetAddr)pnode->addr))
pnode->fDisconnect = true;
}
@@ -542,6 +582,8 @@ bool CConnman::Unban(const CSubNet &subNet) {
void CConnman::GetBanned(banmap_t &banMap)
{
LOCK(cs_setBanned);
+ // Sweep the banlist so expired bans are not returned
+ SweepBanned();
banMap = setBanned; //create a thread safe copy
}
@@ -566,7 +608,7 @@ void CConnman::SweepBanned()
{
setBanned.erase(it++);
setBannedIsDirty = true;
- LogPrint("net", "%s: Removed banned node ip/subnet from banlist.dat: %s\n", __func__, subNet.ToString());
+ LogPrint(BCLog::NET, "%s: Removed banned node ip/subnet from banlist.dat: %s\n", __func__, subNet.ToString());
}
else
++it;
@@ -587,17 +629,37 @@ void CConnman::SetBannedSetDirty(bool dirty)
bool CConnman::IsWhitelistedRange(const CNetAddr &addr) {
- LOCK(cs_vWhitelistedRange);
- BOOST_FOREACH(const CSubNet& subnet, vWhitelistedRange) {
+ for (const CSubNet& subnet : vWhitelistedRange) {
if (subnet.Match(addr))
return true;
}
return false;
}
-void CConnman::AddWhitelistedRange(const CSubNet &subnet) {
- LOCK(cs_vWhitelistedRange);
- vWhitelistedRange.push_back(subnet);
+std::string CNode::GetAddrName() const {
+ LOCK(cs_addrName);
+ return addrName;
+}
+
+void CNode::MaybeSetAddrName(const std::string& addrNameIn) {
+ LOCK(cs_addrName);
+ if (addrName.empty()) {
+ addrName = addrNameIn;
+ }
+}
+
+CService CNode::GetAddrLocal() const {
+ LOCK(cs_addrLocal);
+ return addrLocal;
+}
+
+void CNode::SetAddrLocal(const CService& addrLocalIn) {
+ LOCK(cs_addrLocal);
+ if (addrLocal.IsValid()) {
+ error("Addr local already set for node: %i. Refusing to change from %s to %s", id, addrLocal.ToString(), addrLocalIn.ToString());
+ } else {
+ addrLocal = addrLocalIn;
+ }
}
#undef X
@@ -607,21 +669,34 @@ void CNode::copyStats(CNodeStats &stats)
stats.nodeid = this->GetId();
X(nServices);
X(addr);
- X(fRelayTxes);
+ X(addrBind);
+ {
+ LOCK(cs_filter);
+ X(fRelayTxes);
+ }
X(nLastSend);
X(nLastRecv);
X(nTimeConnected);
X(nTimeOffset);
- X(addrName);
+ stats.addrName = GetAddrName();
X(nVersion);
- X(cleanSubVer);
+ {
+ LOCK(cs_SubVer);
+ X(cleanSubVer);
+ }
X(fInbound);
X(fAddnode);
X(nStartingHeight);
- X(nSendBytes);
- X(mapSendBytesPerMsgCmd);
- X(nRecvBytes);
- X(mapRecvBytesPerMsgCmd);
+ {
+ LOCK(cs_vSend);
+ X(mapSendBytesPerMsgCmd);
+ X(nSendBytes);
+ }
+ {
+ LOCK(cs_vRecv);
+ X(mapRecvBytesPerMsgCmd);
+ X(nRecvBytes);
+ }
X(fWhitelisted);
// It is common for nodes with good ping times to suddenly become lagged,
@@ -641,7 +716,8 @@ void CNode::copyStats(CNodeStats &stats)
stats.dPingWait = (((double)nPingUsecWait) / 1e6);
// Leave string empty if addrLocal invalid (not filled in yet)
- stats.addrLocal = addrLocal.IsValid() ? addrLocal.ToString() : "";
+ CService addrLocalUnlocked = GetAddrLocal();
+ stats.addrLocal = addrLocalUnlocked.IsValid() ? addrLocalUnlocked.ToString() : "";
}
#undef X
@@ -649,6 +725,7 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete
{
complete = false;
int64_t nTimeMicros = GetTimeMicros();
+ LOCK(cs_vRecv);
nLastRecv = nTimeMicros / 1000000;
nRecvBytes += nBytes;
while (nBytes > 0) {
@@ -668,10 +745,10 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete
handled = msg.readData(pch, nBytes);
if (handled < 0)
- return false;
+ return false;
if (msg.in_data && msg.hdr.nMessageSize > MAX_PROTOCOL_MESSAGE_LENGTH) {
- LogPrint("net", "Oversized message from peer=%i, disconnecting\n", GetId());
+ LogPrint(BCLog::NET, "Oversized message from peer=%i, disconnecting\n", GetId());
return false;
}
@@ -696,6 +773,33 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete
return true;
}
+void CNode::SetSendVersion(int nVersionIn)
+{
+ // Send version may only be changed in the version message, and
+ // only one version message is allowed per session. We can therefore
+ // treat this value as const and even atomic as long as it's only used
+ // once a version message has been successfully processed. Any attempt to
+ // set this twice is an error.
+ if (nSendVersion != 0) {
+ error("Send version already set for node: %i. Refusing to change from %i to %i", id, nSendVersion, nVersionIn);
+ } else {
+ nSendVersion = nVersionIn;
+ }
+}
+
+int CNode::GetSendVersion() const
+{
+ // The send version should always be explicitly set to
+ // INIT_PROTO_VERSION rather than using this value until SetSendVersion
+ // has been called.
+ if (nSendVersion == 0) {
+ error("Requesting unset send version for node: %i. Using %i", id, INIT_PROTO_VERSION);
+ return INIT_PROTO_VERSION;
+ }
+ return nSendVersion;
+}
+
+
int CNetMessage::readHeader(const char *pch, unsigned int nBytes)
{
// copy data to temporary parsing buffer
@@ -719,7 +823,7 @@ int CNetMessage::readHeader(const char *pch, unsigned int nBytes)
// reject messages larger than MAX_SIZE
if (hdr.nMessageSize > MAX_SIZE)
- return -1;
+ return -1;
// switch state to reading message data
in_data = true;
@@ -761,7 +865,7 @@ const uint256& CNetMessage::GetMessageHash() const
// requires LOCK(cs_vSend)
-size_t CConnman::SocketSendData(CNode *pnode)
+size_t CConnman::SocketSendData(CNode *pnode) const
{
auto it = pnode->vSendMsg.begin();
size_t nSentSize = 0;
@@ -769,9 +873,15 @@ size_t CConnman::SocketSendData(CNode *pnode)
while (it != pnode->vSendMsg.end()) {
const auto &data = *it;
assert(data.size() > pnode->nSendOffset);
- int nBytes = send(pnode->hSocket, reinterpret_cast<const char*>(data.data()) + pnode->nSendOffset, data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT);
+ int nBytes = 0;
+ {
+ LOCK(pnode->cs_hSocket);
+ if (pnode->hSocket == INVALID_SOCKET)
+ break;
+ nBytes = send(pnode->hSocket, reinterpret_cast<const char*>(data.data()) + pnode->nSendOffset, data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT);
+ }
if (nBytes > 0) {
- pnode->nLastSend = GetTime();
+ pnode->nLastSend = GetSystemTimeInSeconds();
pnode->nSendBytes += nBytes;
pnode->nSendOffset += nBytes;
nSentSize += nBytes;
@@ -866,17 +976,17 @@ bool CConnman::AttemptToEvictConnection()
{
LOCK(cs_vNodes);
- BOOST_FOREACH(CNode *node, vNodes) {
+ for (const CNode* node : vNodes) {
if (node->fWhitelisted)
continue;
if (!node->fInbound)
continue;
if (node->fDisconnect)
continue;
- NodeEvictionCandidate candidate = {node->id, node->nTimeConnected, node->nMinPingUsecTime,
+ NodeEvictionCandidate candidate = {node->GetId(), node->nTimeConnected, node->nMinPingUsecTime,
node->nLastBlockTime, node->nLastTXTime,
(node->nServices & nRelevantServices) == nRelevantServices,
- node->fRelayTxes, node->pfilter != NULL, node->addr, node->nKeyedNetGroup};
+ node->fRelayTxes, node->pfilter != nullptr, node->addr, node->nKeyedNetGroup};
vEvictionCandidates.push_back(candidate);
}
}
@@ -926,7 +1036,7 @@ bool CConnman::AttemptToEvictConnection()
unsigned int nMostConnections = 0;
int64_t nMostConnectionsTime = 0;
std::map<uint64_t, std::vector<NodeEvictionCandidate> > mapNetGroupNodes;
- BOOST_FOREACH(const NodeEvictionCandidate &node, vEvictionCandidates) {
+ for (const NodeEvictionCandidate &node : vEvictionCandidates) {
mapNetGroupNodes[node.nKeyedNetGroup].push_back(node);
int64_t grouptime = mapNetGroupNodes[node.nKeyedNetGroup][0].nTimeConnected;
size_t groupsize = mapNetGroupNodes[node.nKeyedNetGroup].size();
@@ -944,9 +1054,9 @@ bool CConnman::AttemptToEvictConnection()
// Disconnect from the network group with the most connections
NodeId evicted = vEvictionCandidates.front().id;
LOCK(cs_vNodes);
- for(std::vector<CNode*>::const_iterator it(vNodes.begin()); it != vNodes.end(); ++it) {
- if ((*it)->GetId() == evicted) {
- (*it)->fDisconnect = true;
+ for (CNode* pnode : vNodes) {
+ if (pnode->GetId() == evicted) {
+ pnode->fDisconnect = true;
return true;
}
}
@@ -961,16 +1071,18 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
int nInbound = 0;
int nMaxInbound = nMaxConnections - (nMaxOutbound + nMaxFeeler);
- if (hSocket != INVALID_SOCKET)
- if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
+ if (hSocket != INVALID_SOCKET) {
+ if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) {
LogPrintf("Warning: Unknown socket family\n");
+ }
+ }
bool whitelisted = hListenSocket.whitelisted || IsWhitelistedRange(addr);
{
LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (pnode->fInbound)
- nInbound++;
+ for (const CNode* pnode : vNodes) {
+ if (pnode->fInbound) nInbound++;
+ }
}
if (hSocket == INVALID_SOCKET)
@@ -996,12 +1108,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
// According to the internet TCP_NODELAY is not carried into accepted sockets
// on all platforms. Set it again here just to be sure.
- int set = 1;
-#ifdef WIN32
- setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&set, sizeof(int));
-#else
- setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&set, sizeof(int));
-#endif
+ SetSocketNoDelay(hSocket);
if (IsBanned(addr) && !whitelisted)
{
@@ -1014,7 +1121,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
{
if (!AttemptToEvictConnection()) {
// No connection to evict, disconnect the new connection
- LogPrint("net", "failed to find an eviction candidate - connection dropped (full)\n");
+ LogPrint(BCLog::NET, "failed to find an eviction candidate - connection dropped (full)\n");
CloseSocket(hSocket);
return;
}
@@ -1022,13 +1129,14 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
NodeId id = GetNewNodeId();
uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
+ CAddress addr_bind = GetBindAddress(hSocket);
- CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, "", true);
+ CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", true);
pnode->AddRef();
pnode->fWhitelisted = whitelisted;
- GetNodeSignals().InitializeNode(pnode, *this);
+ m_msgproc->InitializeNode(pnode);
- LogPrint("net", "connection from %s accepted\n", addr.ToString());
+ LogPrint(BCLog::NET, "connection from %s accepted\n", addr.ToString());
{
LOCK(cs_vNodes);
@@ -1048,7 +1156,7 @@ void CConnman::ThreadSocketHandler()
LOCK(cs_vNodes);
// Disconnect unused nodes
std::vector<CNode*> vNodesCopy = vNodes;
- BOOST_FOREACH(CNode* pnode, vNodesCopy)
+ for (CNode* pnode : vNodesCopy)
{
if (pnode->fDisconnect)
{
@@ -1070,23 +1178,21 @@ void CConnman::ThreadSocketHandler()
{
// Delete disconnected nodes
std::list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;
- BOOST_FOREACH(CNode* pnode, vNodesDisconnectedCopy)
+ for (CNode* pnode : vNodesDisconnectedCopy)
{
// wait until threads are done using it
- if (pnode->GetRefCount() <= 0)
- {
+ if (pnode->GetRefCount() <= 0) {
bool fDelete = false;
{
- TRY_LOCK(pnode->cs_vSend, lockSend);
- if (lockSend)
- {
- TRY_LOCK(pnode->cs_inventory, lockInv);
- if (lockInv)
- fDelete = true;
+ TRY_LOCK(pnode->cs_inventory, lockInv);
+ if (lockInv) {
+ TRY_LOCK(pnode->cs_vSend, lockSend);
+ if (lockSend) {
+ fDelete = true;
+ }
}
}
- if (fDelete)
- {
+ if (fDelete) {
vNodesDisconnected.remove(pnode);
DeleteNode(pnode);
}
@@ -1120,7 +1226,7 @@ void CConnman::ThreadSocketHandler()
SOCKET hSocketMax = 0;
bool have_fds = false;
- BOOST_FOREACH(const ListenSocket& hListenSocket, vhListenSocket) {
+ for (const ListenSocket& hListenSocket : vhListenSocket) {
FD_SET(hListenSocket.socket, &fdsetRecv);
hSocketMax = std::max(hSocketMax, hListenSocket.socket);
have_fds = true;
@@ -1128,14 +1234,8 @@ void CConnman::ThreadSocketHandler()
{
LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
+ for (CNode* pnode : vNodes)
{
- if (pnode->hSocket == INVALID_SOCKET)
- continue;
- FD_SET(pnode->hSocket, &fdsetError);
- hSocketMax = std::max(hSocketMax, pnode->hSocket);
- have_fds = true;
-
// Implement the following logic:
// * If there is data to send, select() for sending data. As this only
// happens when optimistic write failed, we choose to first drain the
@@ -1146,18 +1246,28 @@ void CConnman::ThreadSocketHandler()
// receiving data.
// * Hand off all complete messages to the processor, to be handled without
// blocking here.
+
+ bool select_recv = !pnode->fPauseRecv;
+ bool select_send;
{
- TRY_LOCK(pnode->cs_vSend, lockSend);
- if (lockSend) {
- if (!pnode->vSendMsg.empty()) {
- FD_SET(pnode->hSocket, &fdsetSend);
- continue;
- }
- }
+ LOCK(pnode->cs_vSend);
+ select_send = !pnode->vSendMsg.empty();
}
- {
- if (!pnode->fPauseRecv)
- FD_SET(pnode->hSocket, &fdsetRecv);
+
+ LOCK(pnode->cs_hSocket);
+ if (pnode->hSocket == INVALID_SOCKET)
+ continue;
+
+ FD_SET(pnode->hSocket, &fdsetError);
+ hSocketMax = std::max(hSocketMax, pnode->hSocket);
+ have_fds = true;
+
+ if (select_send) {
+ FD_SET(pnode->hSocket, &fdsetSend);
+ continue;
+ }
+ if (select_recv) {
+ FD_SET(pnode->hSocket, &fdsetRecv);
}
}
}
@@ -1185,7 +1295,7 @@ void CConnman::ThreadSocketHandler()
//
// Accept new connections
//
- BOOST_FOREACH(const ListenSocket& hListenSocket, vhListenSocket)
+ for (const ListenSocket& hListenSocket : vhListenSocket)
{
if (hListenSocket.socket != INVALID_SOCKET && FD_ISSET(hListenSocket.socket, &fdsetRecv))
{
@@ -1200,10 +1310,10 @@ void CConnman::ThreadSocketHandler()
{
LOCK(cs_vNodes);
vNodesCopy = vNodes;
- BOOST_FOREACH(CNode* pnode, vNodesCopy)
+ for (CNode* pnode : vNodesCopy)
pnode->AddRef();
}
- BOOST_FOREACH(CNode* pnode, vNodesCopy)
+ for (CNode* pnode : vNodesCopy)
{
if (interruptNet)
return;
@@ -1211,56 +1321,68 @@ void CConnman::ThreadSocketHandler()
//
// Receive
//
- if (pnode->hSocket == INVALID_SOCKET)
- continue;
- if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))
+ bool recvSet = false;
+ bool sendSet = false;
+ bool errorSet = false;
{
+ LOCK(pnode->cs_hSocket);
+ if (pnode->hSocket == INVALID_SOCKET)
+ continue;
+ recvSet = FD_ISSET(pnode->hSocket, &fdsetRecv);
+ sendSet = FD_ISSET(pnode->hSocket, &fdsetSend);
+ errorSet = FD_ISSET(pnode->hSocket, &fdsetError);
+ }
+ if (recvSet || errorSet)
+ {
+ // typical socket buffer is 8K-64K
+ char pchBuf[0x10000];
+ int nBytes = 0;
{
- {
- // typical socket buffer is 8K-64K
- char pchBuf[0x10000];
- int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
- if (nBytes > 0)
- {
- bool notify = false;
- if (!pnode->ReceiveMsgBytes(pchBuf, nBytes, notify))
- pnode->CloseSocketDisconnect();
- RecordBytesRecv(nBytes);
- if (notify) {
- size_t nSizeAdded = 0;
- auto it(pnode->vRecvMsg.begin());
- for (; it != pnode->vRecvMsg.end(); ++it) {
- if (!it->complete())
- break;
- nSizeAdded += it->vRecv.size() + CMessageHeader::HEADER_SIZE;
- }
- {
- LOCK(pnode->cs_vProcessMsg);
- pnode->vProcessMsg.splice(pnode->vProcessMsg.end(), pnode->vRecvMsg, pnode->vRecvMsg.begin(), it);
- pnode->nProcessQueueSize += nSizeAdded;
- pnode->fPauseRecv = pnode->nProcessQueueSize > nReceiveFloodSize;
- }
- WakeMessageHandler();
- }
- }
- else if (nBytes == 0)
- {
- // socket closed gracefully
- if (!pnode->fDisconnect)
- LogPrint("net", "socket closed\n");
- pnode->CloseSocketDisconnect();
+ LOCK(pnode->cs_hSocket);
+ if (pnode->hSocket == INVALID_SOCKET)
+ continue;
+ nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
+ }
+ if (nBytes > 0)
+ {
+ bool notify = false;
+ if (!pnode->ReceiveMsgBytes(pchBuf, nBytes, notify))
+ pnode->CloseSocketDisconnect();
+ RecordBytesRecv(nBytes);
+ if (notify) {
+ size_t nSizeAdded = 0;
+ auto it(pnode->vRecvMsg.begin());
+ for (; it != pnode->vRecvMsg.end(); ++it) {
+ if (!it->complete())
+ break;
+ nSizeAdded += it->vRecv.size() + CMessageHeader::HEADER_SIZE;
}
- else if (nBytes < 0)
{
- // error
- int nErr = WSAGetLastError();
- if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
- {
- if (!pnode->fDisconnect)
- LogPrintf("socket recv error %s\n", NetworkErrorString(nErr));
- pnode->CloseSocketDisconnect();
- }
+ LOCK(pnode->cs_vProcessMsg);
+ pnode->vProcessMsg.splice(pnode->vProcessMsg.end(), pnode->vRecvMsg, pnode->vRecvMsg.begin(), it);
+ pnode->nProcessQueueSize += nSizeAdded;
+ pnode->fPauseRecv = pnode->nProcessQueueSize > nReceiveFloodSize;
}
+ WakeMessageHandler();
+ }
+ }
+ else if (nBytes == 0)
+ {
+ // socket closed gracefully
+ if (!pnode->fDisconnect) {
+ LogPrint(BCLog::NET, "socket closed\n");
+ }
+ pnode->CloseSocketDisconnect();
+ }
+ else if (nBytes < 0)
+ {
+ // error
+ int nErr = WSAGetLastError();
+ if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
+ {
+ if (!pnode->fDisconnect)
+ LogPrintf("socket recv error %s\n", NetworkErrorString(nErr));
+ pnode->CloseSocketDisconnect();
}
}
}
@@ -1268,28 +1390,24 @@ void CConnman::ThreadSocketHandler()
//
// Send
//
- if (pnode->hSocket == INVALID_SOCKET)
- continue;
- if (FD_ISSET(pnode->hSocket, &fdsetSend))
+ if (sendSet)
{
- TRY_LOCK(pnode->cs_vSend, lockSend);
- if (lockSend) {
- size_t nBytes = SocketSendData(pnode);
- if (nBytes) {
- RecordBytesSent(nBytes);
- }
+ LOCK(pnode->cs_vSend);
+ size_t nBytes = SocketSendData(pnode);
+ if (nBytes) {
+ RecordBytesSent(nBytes);
}
}
//
// Inactivity checking
//
- int64_t nTime = GetTime();
+ int64_t nTime = GetSystemTimeInSeconds();
if (nTime - pnode->nTimeConnected > 60)
{
if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)
{
- LogPrint("net", "socket no message in first 60 seconds, %d %d from %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0, pnode->id);
+ LogPrint(BCLog::NET, "socket no message in first 60 seconds, %d %d from %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0, pnode->GetId());
pnode->fDisconnect = true;
}
else if (nTime - pnode->nLastSend > TIMEOUT_INTERVAL)
@@ -1307,11 +1425,16 @@ void CConnman::ThreadSocketHandler()
LogPrintf("ping timeout: %fs\n", 0.000001 * (GetTimeMicros() - pnode->nPingUsecStart));
pnode->fDisconnect = true;
}
+ else if (!pnode->fSuccessfullyConnected)
+ {
+ LogPrintf("version handshake timeout from %d\n", pnode->GetId());
+ pnode->fDisconnect = true;
+ }
}
}
{
LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodesCopy)
+ for (CNode* pnode : vNodesCopy)
pnode->Release();
}
}
@@ -1335,9 +1458,9 @@ void CConnman::WakeMessageHandler()
void ThreadMapPort()
{
std::string port = strprintf("%u", GetListenPort());
- const char * multicastif = 0;
- const char * minissdpdpath = 0;
- struct UPNPDev * devlist = 0;
+ const char * multicastif = nullptr;
+ const char * minissdpdpath = nullptr;
+ struct UPNPDev * devlist = nullptr;
char lanaddr[64];
#ifndef UPNPDISCOVER_SUCCESS
@@ -1407,13 +1530,13 @@ void ThreadMapPort()
{
r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", 0);
LogPrintf("UPNP_DeletePortMapping() returned: %d\n", r);
- freeUPNPDevlist(devlist); devlist = 0;
+ freeUPNPDevlist(devlist); devlist = nullptr;
FreeUPNPUrls(&urls);
throw;
}
} else {
LogPrintf("No valid UPnP IGDs found\n");
- freeUPNPDevlist(devlist); devlist = 0;
+ freeUPNPDevlist(devlist); devlist = nullptr;
if (r != 0)
FreeUPNPUrls(&urls);
}
@@ -1421,7 +1544,7 @@ void ThreadMapPort()
void MapPort(bool fUseUPnP)
{
- static boost::thread* upnp_thread = NULL;
+ static boost::thread* upnp_thread = nullptr;
if (fUseUPnP)
{
@@ -1436,7 +1559,7 @@ void MapPort(bool fUseUPnP)
upnp_thread->interrupt();
upnp_thread->join();
delete upnp_thread;
- upnp_thread = NULL;
+ upnp_thread = nullptr;
}
}
@@ -1472,7 +1595,7 @@ void CConnman::ThreadDNSAddressSeed()
// creating fewer identifying DNS requests, reduces trust by giving seeds
// less influence on the network topology, and reduces traffic to the seeds.
if ((addrman.size() > 0) &&
- (!GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED))) {
+ (!gArgs.GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED))) {
if (!interruptNet.sleep_for(std::chrono::seconds(11)))
return;
@@ -1492,16 +1615,24 @@ void CConnman::ThreadDNSAddressSeed()
LogPrintf("Loading addresses from DNS seeds (could take a while)\n");
- BOOST_FOREACH(const CDNSSeedData &seed, vSeeds) {
+ for (const CDNSSeedData &seed : vSeeds) {
+ if (interruptNet) {
+ return;
+ }
if (HaveNameProxy()) {
AddOneShot(seed.host);
} else {
std::vector<CNetAddr> vIPs;
std::vector<CAddress> vAdd;
ServiceFlags requiredServiceBits = nRelevantServices;
- if (LookupHost(GetDNSHost(seed, &requiredServiceBits).c_str(), vIPs, 0, true))
+ std::string host = GetDNSHost(seed, &requiredServiceBits);
+ CNetAddr resolveSource;
+ if (!resolveSource.SetInternal(host)) {
+ continue;
+ }
+ if (LookupHost(host.c_str(), vIPs, 0, true))
{
- BOOST_FOREACH(const CNetAddr& ip, vIPs)
+ for (const CNetAddr& ip : vIPs)
{
int nOneDay = 24*3600;
CAddress addr = CAddress(CService(ip, Params().GetDefaultPort()), requiredServiceBits);
@@ -1509,15 +1640,7 @@ void CConnman::ThreadDNSAddressSeed()
vAdd.push_back(addr);
found++;
}
- }
- // TODO: The seed name resolve may fail, yielding an IP of [::], which results in
- // addrman assigning the same source to results from different seeds.
- // This should switch to a hard-coded stable dummy IP for each seed name, so that the
- // resolve is not required at all.
- if (!vIPs.empty()) {
- CService seedSource;
- Lookup(seed.name.c_str(), seedSource, 0, true);
- addrman.Add(vAdd, seedSource);
+ addrman.Add(vAdd, resolveSource);
}
}
}
@@ -1543,7 +1666,7 @@ void CConnman::DumpAddresses()
CAddrDB adb;
adb.Write(addrman);
- LogPrint("net", "Flushed %d addresses to peers.dat %dms\n",
+ LogPrint(BCLog::NET, "Flushed %d addresses to peers.dat %dms\n",
addrman.size(), GetTimeMillis() - nStart);
}
@@ -1571,18 +1694,18 @@ void CConnman::ProcessOneShot()
}
}
-void CConnman::ThreadOpenConnections()
+void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
{
// Connect to specific addresses
- if (mapMultiArgs.count("-connect") && mapMultiArgs.at("-connect").size() > 0)
+ if (!connect.empty())
{
for (int64_t nLoop = 0;; nLoop++)
{
ProcessOneShot();
- BOOST_FOREACH(const std::string& strAddr, mapMultiArgs.at("-connect"))
+ for (const std::string& strAddr : connect)
{
CAddress addr(CService(), NODE_NONE);
- OpenNetworkConnection(addr, false, NULL, strAddr.c_str());
+ OpenNetworkConnection(addr, false, nullptr, strAddr.c_str());
for (int i = 0; i < 10 && i < nLoop; i++)
{
if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
@@ -1616,7 +1739,7 @@ void CConnman::ThreadOpenConnections()
if (!done) {
LogPrintf("Adding fixed seed nodes as DNS doesn't seem to be available.\n");
CNetAddr local;
- LookupHost("127.0.0.1", local, false);
+ local.SetInternal("fixedseeds");
addrman.Add(convertSeed6(Params().FixedSeeds()), local);
done = true;
}
@@ -1630,11 +1753,17 @@ void CConnman::ThreadOpenConnections()
// Only connect out to one peer per network group (/16 for IPv4).
// Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
int nOutbound = 0;
+ int nOutboundRelevant = 0;
std::set<std::vector<unsigned char> > setConnected;
{
LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes) {
+ for (CNode* pnode : vNodes) {
if (!pnode->fInbound && !pnode->fAddnode) {
+
+ // Count the peers that have all relevant services
+ if (pnode->fSuccessfullyConnected && !pnode->fFeeler && ((pnode->nServices & nRelevantServices) == nRelevantServices)) {
+ nOutboundRelevant++;
+ }
// Netgroups for inbound and addnode peers are not excluded because our goal here
// is to not use multiple of our limited outbound slots on a single netgroup
// but inbound and addnode peers do not use our outbound slots. Inbound peers
@@ -1652,9 +1781,9 @@ void CConnman::ThreadOpenConnections()
// * Increase the number of connectable addresses in the tried table.
//
// Method:
- // * Choose a random address from new and attempt to connect to it if we can connect
+ // * Choose a random address from new and attempt to connect to it if we can connect
// successfully it is added to tried.
- // * Start attempting feeler connections only after node finishes making outbound
+ // * Start attempting feeler connections only after node finishes making outbound
// connections.
// * Only make a feeler connection once every few minutes.
//
@@ -1698,14 +1827,27 @@ void CConnman::ThreadOpenConnections()
continue;
// only consider nodes missing relevant services after 40 failed attempts and only if less than half the outbound are up.
- if ((addr.nServices & nRelevantServices) != nRelevantServices && (nTries < 40 || nOutbound >= (nMaxOutbound >> 1)))
+ ServiceFlags nRequiredServices = nRelevantServices;
+ if (nTries >= 40 && nOutbound < (nMaxOutbound >> 1)) {
+ nRequiredServices = REQUIRED_SERVICES;
+ }
+
+ if ((addr.nServices & nRequiredServices) != nRequiredServices) {
continue;
+ }
// do not allow non-default ports, unless after 50 invalid addresses selected already
if (addr.GetPort() != Params().GetDefaultPort() && nTries < 50)
continue;
addrConnect = addr;
+
+ // regardless of the services assumed to be available, only require the minimum if half or more outbound have relevant services
+ if (nOutboundRelevant >= (nMaxOutbound >> 1)) {
+ addrConnect.nServices = REQUIRED_SERVICES;
+ } else {
+ addrConnect.nServices = nRequiredServices;
+ }
break;
}
@@ -1716,10 +1858,10 @@ void CConnman::ThreadOpenConnections()
int randsleep = GetRandInt(FEELER_SLEEP_WINDOW * 1000);
if (!interruptNet.sleep_for(std::chrono::milliseconds(randsleep)))
return;
- LogPrint("net", "Making feeler connection to %s\n", addrConnect.ToString());
+ LogPrint(BCLog::NET, "Making feeler connection to %s\n", addrConnect.ToString());
}
- OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant, NULL, false, fFeeler);
+ OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant, nullptr, false, fFeeler);
}
}
}
@@ -1732,8 +1874,7 @@ std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo()
{
LOCK(cs_vAddedNodes);
ret.reserve(vAddedNodes.size());
- BOOST_FOREACH(const std::string& strAddNode, vAddedNodes)
- lAddresses.push_back(strAddNode);
+ std::copy(vAddedNodes.cbegin(), vAddedNodes.cend(), std::back_inserter(lAddresses));
}
@@ -1746,13 +1887,14 @@ std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo()
if (pnode->addr.IsValid()) {
mapConnected[pnode->addr] = pnode->fInbound;
}
- if (!pnode->addrName.empty()) {
- mapConnectedByName[pnode->addrName] = std::make_pair(pnode->fInbound, static_cast<const CService&>(pnode->addr));
+ std::string addrName = pnode->GetAddrName();
+ if (!addrName.empty()) {
+ mapConnectedByName[std::move(addrName)] = std::make_pair(pnode->fInbound, static_cast<const CService&>(pnode->addr));
}
}
}
- BOOST_FOREACH(const std::string& strAddNode, lAddresses) {
+ for (const std::string& strAddNode : lAddresses) {
CService service(LookupNumeric(strAddNode.c_str(), Params().GetDefaultPort()));
if (service.IsValid()) {
// strAddNode is an IP:port
@@ -1778,12 +1920,6 @@ std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo()
void CConnman::ThreadOpenAddedConnections()
{
- {
- LOCK(cs_vAddedNodes);
- if (mapMultiArgs.count("-addnode"))
- vAddedNodes = mapMultiArgs.at("-addnode");
- }
-
while (true)
{
CSemaphoreGrant grant(*semAddnode);
@@ -1796,11 +1932,9 @@ void CConnman::ThreadOpenAddedConnections()
// the addednodeinfo state might change.
break;
}
- // If strAddedNode is an IP/port, decode it immediately, so
- // OpenNetworkConnection can detect existing connections to that IP/port.
tried = true;
- CService service(LookupNumeric(info.strAddedNode.c_str(), Params().GetDefaultPort()));
- OpenNetworkConnection(CAddress(service, NODE_NONE), false, &grant, info.strAddedNode.c_str(), false, false, true);
+ CAddress addr(CService(), NODE_NONE);
+ OpenNetworkConnection(addr, false, &grant, info.strAddedNode.c_str(), false, false, true);
if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
return;
}
@@ -1844,6 +1978,12 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
if (fAddnode)
pnode->fAddnode = true;
+ m_msgproc->InitializeNode(pnode);
+ {
+ LOCK(cs_vNodes);
+ vNodes.push_back(pnode);
+ }
+
return true;
}
@@ -1855,37 +1995,36 @@ void CConnman::ThreadMessageHandler()
{
LOCK(cs_vNodes);
vNodesCopy = vNodes;
- BOOST_FOREACH(CNode* pnode, vNodesCopy) {
+ for (CNode* pnode : vNodesCopy) {
pnode->AddRef();
}
}
bool fMoreWork = false;
- BOOST_FOREACH(CNode* pnode, vNodesCopy)
+ for (CNode* pnode : vNodesCopy)
{
if (pnode->fDisconnect)
continue;
// Receive messages
- bool fMoreNodeWork = GetNodeSignals().ProcessMessages(pnode, *this, flagInterruptMsgProc);
+ bool fMoreNodeWork = m_msgproc->ProcessMessages(pnode, flagInterruptMsgProc);
fMoreWork |= (fMoreNodeWork && !pnode->fPauseSend);
if (flagInterruptMsgProc)
return;
-
// Send messages
{
- TRY_LOCK(pnode->cs_vSend, lockSend);
- if (lockSend)
- GetNodeSignals().SendMessages(pnode, *this, flagInterruptMsgProc);
+ LOCK(pnode->cs_sendProcessing);
+ m_msgproc->SendMessages(pnode, flagInterruptMsgProc);
}
+
if (flagInterruptMsgProc)
return;
}
{
LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodesCopy)
+ for (CNode* pnode : vNodesCopy)
pnode->Release();
}
@@ -1949,6 +2088,7 @@ bool CConnman::BindListenPort(const CService &addrBind, std::string& strError, b
// Set to non-blocking, incoming connections will also inherit this
if (!SetSocketNonBlocking(hListenSocket, true)) {
+ CloseSocket(hListenSocket);
strError = strprintf("BindListenPort: Setting listening socket to non-blocking failed, error %s\n", NetworkErrorString(WSAGetLastError()));
LogPrintf("%s\n", strError);
return false;
@@ -2013,7 +2153,7 @@ void Discover(boost::thread_group& threadGroup)
std::vector<CNetAddr> vaddr;
if (LookupHost(pszHostName, vaddr, 0, true))
{
- BOOST_FOREACH (const CNetAddr &addr, vaddr)
+ for (const CNetAddr &addr : vaddr)
{
if (AddLocal(addr, LOCAL_IF))
LogPrintf("%s: %s - %s\n", __func__, pszHostName, addr.ToString());
@@ -2025,9 +2165,9 @@ void Discover(boost::thread_group& threadGroup)
struct ifaddrs* myaddrs;
if (getifaddrs(&myaddrs) == 0)
{
- for (struct ifaddrs* ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next)
+ for (struct ifaddrs* ifa = myaddrs; ifa != nullptr; ifa = ifa->ifa_next)
{
- if (ifa->ifa_addr == NULL) continue;
+ if (ifa->ifa_addr == nullptr) continue;
if ((ifa->ifa_flags & IFF_UP) == 0) continue;
if (strcmp(ifa->ifa_name, "lo") == 0) continue;
if (strcmp(ifa->ifa_name, "lo0") == 0) continue;
@@ -2053,20 +2193,20 @@ void Discover(boost::thread_group& threadGroup)
void CConnman::SetNetworkActive(bool active)
{
- if (fDebug) {
- LogPrint("net", "SetNetworkActive: %s\n", active);
+ LogPrint(BCLog::NET, "SetNetworkActive: %s\n", active);
+
+ if (fNetworkActive == active) {
+ return;
}
- if (!active) {
- fNetworkActive = false;
+ fNetworkActive = active;
+ if (!fNetworkActive) {
LOCK(cs_vNodes);
// Close sockets to all nodes
- BOOST_FOREACH(CNode* pnode, vNodes) {
+ for (CNode* pnode : vNodes) {
pnode->CloseSocketDisconnect();
}
- } else {
- fNetworkActive = true;
}
uiInterface.NotifyNetworkActiveChanged(fNetworkActive);
@@ -2080,14 +2220,12 @@ CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSe
nLastNodeId = 0;
nSendBufferMaxSize = 0;
nReceiveFloodSize = 0;
- semOutbound = NULL;
- semAddnode = NULL;
- nMaxConnections = 0;
- nMaxOutbound = 0;
- nMaxAddnode = 0;
- nBestHeight = 0;
- clientInterface = NULL;
+ semOutbound = nullptr;
+ semAddnode = nullptr;
flagInterruptMsgProc = false;
+
+ Options connOptions;
+ Init(connOptions);
}
NodeId CConnman::GetNewNodeId()
@@ -2095,31 +2233,62 @@ NodeId CConnman::GetNewNodeId()
return nLastNodeId.fetch_add(1, std::memory_order_relaxed);
}
-bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options connOptions)
+
+bool CConnman::Bind(const CService &addr, unsigned int flags) {
+ if (!(flags & BF_EXPLICIT) && IsLimited(addr))
+ return false;
+ std::string strError;
+ if (!BindListenPort(addr, strError, (flags & BF_WHITELIST) != 0)) {
+ if ((flags & BF_REPORT_ERROR) && clientInterface) {
+ clientInterface->ThreadSafeMessageBox(strError, "", CClientUIInterface::MSG_ERROR);
+ }
+ return false;
+ }
+ return true;
+}
+
+bool CConnman::InitBinds(const std::vector<CService>& binds, const std::vector<CService>& whiteBinds) {
+ bool fBound = false;
+ for (const auto& addrBind : binds) {
+ fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));
+ }
+ for (const auto& addrBind : whiteBinds) {
+ fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST));
+ }
+ if (binds.empty() && whiteBinds.empty()) {
+ struct in_addr inaddr_any;
+ inaddr_any.s_addr = INADDR_ANY;
+ fBound |= Bind(CService(in6addr_any, GetListenPort()), BF_NONE);
+ fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE);
+ }
+ return fBound;
+}
+
+bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
{
+ Init(connOptions);
+
nTotalBytesRecv = 0;
nTotalBytesSent = 0;
nMaxOutboundTotalBytesSentInCycle = 0;
nMaxOutboundCycleStartTime = 0;
- nRelevantServices = connOptions.nRelevantServices;
- nLocalServices = connOptions.nLocalServices;
- nMaxConnections = connOptions.nMaxConnections;
- nMaxOutbound = std::min((connOptions.nMaxOutbound), nMaxConnections);
- nMaxAddnode = connOptions.nMaxAddnode;
- nMaxFeeler = connOptions.nMaxFeeler;
-
- nSendBufferMaxSize = connOptions.nSendBufferMaxSize;
- nReceiveFloodSize = connOptions.nReceiveFloodSize;
-
- nMaxOutboundLimit = connOptions.nMaxOutboundLimit;
- nMaxOutboundTimeframe = connOptions.nMaxOutboundTimeframe;
+ if (fListen && !InitBinds(connOptions.vBinds, connOptions.vWhiteBinds)) {
+ if (clientInterface) {
+ clientInterface->ThreadSafeMessageBox(
+ _("Failed to listen on any port. Use -listen=0 if you want this."),
+ "", CClientUIInterface::MSG_ERROR);
+ }
+ return false;
+ }
- SetBestHeight(connOptions.nBestHeight);
+ for (const auto& strDest : connOptions.vSeedNodes) {
+ AddOneShot(strDest);
+ }
- clientInterface = connOptions.uiInterface;
- if (clientInterface)
- clientInterface->InitMessage(_("Loading addresses..."));
+ if (clientInterface) {
+ clientInterface->InitMessage(_("Loading P2P addresses..."));
+ }
// Load addresses from peers.dat
int64_t nStart = GetTimeMillis();
{
@@ -2143,7 +2312,7 @@ bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options c
SetBannedSetDirty(false); // no need to write down, just read data
SweepBanned(); // sweep out unused entries
- LogPrint("net", "Loaded %d banned node ips/subnets from banlist.dat %dms\n",
+ LogPrint(BCLog::NET, "Loaded %d banned node ips/subnets from banlist.dat %dms\n",
banmap.size(), GetTimeMillis() - nStart);
} else {
LogPrintf("Invalid or missing banlist.dat; recreating\n");
@@ -2155,11 +2324,11 @@ bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options c
fAddressesInitialized = true;
- if (semOutbound == NULL) {
+ if (semOutbound == nullptr) {
// initialize semaphore
semOutbound = new CSemaphore(std::min((nMaxOutbound + nMaxFeeler), nMaxConnections));
}
- if (semAddnode == NULL) {
+ if (semAddnode == nullptr) {
// initialize semaphore
semAddnode = new CSemaphore(nMaxAddnode);
}
@@ -2167,6 +2336,7 @@ bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options c
//
// Start threads
//
+ assert(m_msgproc);
InterruptSocks5(false);
interruptNet.reset();
flagInterruptMsgProc = false;
@@ -2179,7 +2349,7 @@ bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options c
// Send and receive from sockets, accept connections
threadSocketHandler = std::thread(&TraceThread<std::function<void()> >, "net", std::function<void()>(std::bind(&CConnman::ThreadSocketHandler, this)));
- if (!GetBoolArg("-dnsseed", true))
+ if (!gArgs.GetBoolArg("-dnsseed", true))
LogPrintf("DNS seeding disabled\n");
else
threadDNSAddressSeed = std::thread(&TraceThread<std::function<void()> >, "dnsseed", std::function<void()>(std::bind(&CConnman::ThreadDNSAddressSeed, this)));
@@ -2187,15 +2357,22 @@ bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options c
// Initiate outbound connections from -addnode
threadOpenAddedConnections = std::thread(&TraceThread<std::function<void()> >, "addcon", std::function<void()>(std::bind(&CConnman::ThreadOpenAddedConnections, this)));
- // Initiate outbound connections unless connect=0
- if (!mapMultiArgs.count("-connect") || mapMultiArgs.at("-connect").size() != 1 || mapMultiArgs.at("-connect")[0] != "0")
- threadOpenConnections = std::thread(&TraceThread<std::function<void()> >, "opencon", std::function<void()>(std::bind(&CConnman::ThreadOpenConnections, this)));
+ if (connOptions.m_use_addrman_outgoing && !connOptions.m_specified_outgoing.empty()) {
+ if (clientInterface) {
+ clientInterface->ThreadSafeMessageBox(
+ _("Cannot provide specific connections and have addrman find outgoing connections at the same."),
+ "", CClientUIInterface::MSG_ERROR);
+ }
+ return false;
+ }
+ if (connOptions.m_use_addrman_outgoing || !connOptions.m_specified_outgoing.empty())
+ threadOpenConnections = std::thread(&TraceThread<std::function<void()> >, "opencon", std::function<void()>(std::bind(&CConnman::ThreadOpenConnections, this, connOptions.m_specified_outgoing)));
// Process messages
threadMessageHandler = std::thread(&TraceThread<std::function<void()> >, "msghand", std::function<void()>(std::bind(&CConnman::ThreadMessageHandler, this)));
// Dump network addresses
- scheduler.scheduleEvery(boost::bind(&CConnman::DumpData, this), DUMP_ADDRESSES_INTERVAL);
+ scheduler.scheduleEvery(std::bind(&CConnman::DumpData, this), DUMP_ADDRESSES_INTERVAL * 1000);
return true;
}
@@ -2226,9 +2403,17 @@ void CConnman::Interrupt()
interruptNet();
InterruptSocks5(true);
- if (semOutbound)
- for (int i=0; i<(nMaxOutbound + nMaxFeeler); i++)
+ if (semOutbound) {
+ for (int i=0; i<(nMaxOutbound + nMaxFeeler); i++) {
semOutbound->post();
+ }
+ }
+
+ if (semAddnode) {
+ for (int i=0; i<nMaxAddnode; i++) {
+ semAddnode->post();
+ }
+ }
}
void CConnman::Stop()
@@ -2244,10 +2429,6 @@ void CConnman::Stop()
if (threadSocketHandler.joinable())
threadSocketHandler.join();
- if (semAddnode)
- for (int i=0; i<nMaxAddnode; i++)
- semOutbound->post();
-
if (fAddressesInitialized)
{
DumpData();
@@ -2255,37 +2436,37 @@ void CConnman::Stop()
}
// Close sockets
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (pnode->hSocket != INVALID_SOCKET)
- CloseSocket(pnode->hSocket);
- BOOST_FOREACH(ListenSocket& hListenSocket, vhListenSocket)
+ for (CNode* pnode : vNodes)
+ pnode->CloseSocketDisconnect();
+ for (ListenSocket& hListenSocket : vhListenSocket)
if (hListenSocket.socket != INVALID_SOCKET)
if (!CloseSocket(hListenSocket.socket))
LogPrintf("CloseSocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError()));
// clean up some globals (to help leak detection)
- BOOST_FOREACH(CNode *pnode, vNodes) {
+ for (CNode *pnode : vNodes) {
DeleteNode(pnode);
}
- BOOST_FOREACH(CNode *pnode, vNodesDisconnected) {
+ for (CNode *pnode : vNodesDisconnected) {
DeleteNode(pnode);
}
vNodes.clear();
vNodesDisconnected.clear();
vhListenSocket.clear();
delete semOutbound;
- semOutbound = NULL;
+ semOutbound = nullptr;
delete semAddnode;
- semAddnode = NULL;
+ semAddnode = nullptr;
}
void CConnman::DeleteNode(CNode* pnode)
{
assert(pnode);
bool fUpdateConnectionTime = false;
- GetNodeSignals().FinalizeNode(pnode->GetId(), fUpdateConnectionTime);
- if(fUpdateConnectionTime)
+ m_msgproc->FinalizeNode(pnode->GetId(), fUpdateConnectionTime);
+ if(fUpdateConnectionTime) {
addrman.Connected(pnode->addr);
+ }
delete pnode;
}
@@ -2310,11 +2491,6 @@ void CConnman::MarkAddressGood(const CAddress& addr)
addrman.Good(addr);
}
-void CConnman::AddNewAddress(const CAddress& addr, const CAddress& addrFrom, int64_t nTimePenalty)
-{
- addrman.Add(addr, addrFrom, nTimePenalty);
-}
-
void CConnman::AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty)
{
addrman.Add(vAddr, addrFrom, nTimePenalty);
@@ -2328,9 +2504,8 @@ std::vector<CAddress> CConnman::GetAddresses()
bool CConnman::AddNode(const std::string& strNode)
{
LOCK(cs_vAddedNodes);
- for(std::vector<std::string>::const_iterator it = vAddedNodes.begin(); it != vAddedNodes.end(); ++it) {
- if (strNode == *it)
- return false;
+ for (const std::string& it : vAddedNodes) {
+ if (strNode == it) return false;
}
vAddedNodes.push_back(strNode);
@@ -2356,9 +2531,11 @@ size_t CConnman::GetNodeCount(NumConnections flags)
return vNodes.size();
int nNum = 0;
- for(std::vector<CNode*>::const_iterator it = vNodes.begin(); it != vNodes.end(); ++it)
- if (flags & ((*it)->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT))
+ for (const auto& pnode : vNodes) {
+ if (flags & (pnode->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT)) {
nNum++;
+ }
+ }
return nNum;
}
@@ -2368,34 +2545,15 @@ void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats)
vstats.clear();
LOCK(cs_vNodes);
vstats.reserve(vNodes.size());
- for(std::vector<CNode*>::iterator it = vNodes.begin(); it != vNodes.end(); ++it) {
- CNode* pnode = *it;
- CNodeStats stats;
- pnode->copyStats(stats);
- vstats.push_back(stats);
- }
-}
-
-bool CConnman::DisconnectAddress(const CNetAddr& netAddr)
-{
- if (CNode* pnode = FindNode(netAddr)) {
- pnode->fDisconnect = true;
- return true;
- }
- return false;
-}
-
-bool CConnman::DisconnectSubnet(const CSubNet& subNet)
-{
- if (CNode* pnode = FindNode(subNet)) {
- pnode->fDisconnect = true;
- return true;
+ for (CNode* pnode : vNodes) {
+ vstats.emplace_back();
+ pnode->copyStats(vstats.back());
}
- return false;
}
bool CConnman::DisconnectNode(const std::string& strNode)
{
+ LOCK(cs_vNodes);
if (CNode* pnode = FindNode(strNode)) {
pnode->fDisconnect = true;
return true;
@@ -2406,7 +2564,7 @@ bool CConnman::DisconnectNode(NodeId id)
{
LOCK(cs_vNodes);
for(CNode* pnode : vNodes) {
- if (id == pnode->id) {
+ if (id == pnode->GetId()) {
pnode->fDisconnect = true;
return true;
}
@@ -2414,16 +2572,6 @@ bool CConnman::DisconnectNode(NodeId id)
return false;
}
-void CConnman::RelayTransaction(const CTransaction& tx)
-{
- CInv inv(MSG_TX, tx.GetHash());
- LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
- {
- pnode->PushInventory(inv);
- }
-}
-
void CConnman::RecordBytesRecv(uint64_t bytes)
{
LOCK(cs_totalBytesRecv);
@@ -2548,15 +2696,16 @@ int CConnman::GetBestHeight() const
}
unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; }
-unsigned int CConnman::GetSendBufferSize() const{ return nSendBufferMaxSize; }
-CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const std::string& addrNameIn, bool fInboundIn) :
+CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress &addrBindIn, const std::string& addrNameIn, bool fInboundIn) :
+ nTimeConnected(GetSystemTimeInSeconds()),
addr(addrIn),
+ addrBind(addrBindIn),
fInbound(fInboundIn),
- id(idIn),
nKeyedNetGroup(nKeyedNetGroupIn),
addrKnown(5000, 0.001),
filterInventoryKnown(50000, 0.000001),
+ id(idIn),
nLocalHostNonce(nLocalHostNonceIn),
nLocalServices(nLocalServicesIn),
nMyStartingHeight(nMyStartingHeightIn),
@@ -2570,7 +2719,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
nLastRecv = 0;
nSendBytes = 0;
nRecvBytes = 0;
- nTimeConnected = GetTime();
nTimeOffset = 0;
addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
nVersion = 0;
@@ -2611,14 +2759,15 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
fPauseSend = false;
nProcessQueueSize = 0;
- BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes())
+ for (const std::string &msg : getAllNetMessageTypes())
mapRecvBytesPerMsgCmd[msg] = 0;
mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0;
- if (fLogIPs)
- LogPrint("net", "Added connection to %s peer=%d\n", addrName, id);
- else
- LogPrint("net", "Added connection peer=%d\n", id);
+ if (fLogIPs) {
+ LogPrint(BCLog::NET, "Added connection to %s peer=%d\n", addrName, id);
+ } else {
+ LogPrint(BCLog::NET, "Added connection peer=%d\n", id);
+ }
}
CNode::~CNode()
@@ -2645,7 +2794,7 @@ void CNode::AskFor(const CInv& inv)
nRequestTime = it->second;
else
nRequestTime = 0;
- LogPrint("net", "askfor %s %d (%s) peer=%d\n", inv.ToString(), nRequestTime, DateTimeStrFormat("%H:%M:%S", nRequestTime/1000000), id);
+ LogPrint(BCLog::NET, "askfor %s %d (%s) peer=%d\n", inv.ToString(), nRequestTime, DateTimeStrFormat("%H:%M:%S", nRequestTime/1000000), id);
// Make sure not to reuse time indexes to keep things in the same order
int64_t nNow = GetTimeMicros() - 1000000;
@@ -2663,11 +2812,16 @@ void CNode::AskFor(const CInv& inv)
mapAskFor.insert(std::make_pair(nRequestTime, inv));
}
+bool CConnman::NodeFullyConnected(const CNode* pnode)
+{
+ return pnode && pnode->fSuccessfullyConnected && !pnode->fDisconnect;
+}
+
void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg)
{
size_t nMessageSize = msg.data.size();
size_t nTotalSize = nMessageSize + CMessageHeader::HEADER_SIZE;
- LogPrint("net", "sending %s (%d bytes) peer=%d\n", SanitizeString(msg.command.c_str()), nMessageSize, pnode->id);
+ LogPrint(BCLog::NET, "sending %s (%d bytes) peer=%d\n", SanitizeString(msg.command.c_str()), nMessageSize, pnode->GetId());
std::vector<unsigned char> serializedHeader;
serializedHeader.reserve(CMessageHeader::HEADER_SIZE);
@@ -2680,9 +2834,6 @@ void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg)
size_t nBytesSent = 0;
{
LOCK(pnode->cs_vSend);
- if(pnode->hSocket == INVALID_SOCKET) {
- return;
- }
bool optimisticSend(pnode->vSendMsg.empty());
//log total amount of bytes per command
@@ -2708,26 +2859,26 @@ bool CConnman::ForNode(NodeId id, std::function<bool(CNode* pnode)> func)
CNode* found = nullptr;
LOCK(cs_vNodes);
for (auto&& pnode : vNodes) {
- if(pnode->id == id) {
+ if(pnode->GetId() == id) {
found = pnode;
break;
}
}
- return found != nullptr && func(found);
+ return found != nullptr && NodeFullyConnected(found) && func(found);
}
int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) {
return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5);
}
-CSipHasher CConnman::GetDeterministicRandomizer(uint64_t id)
+CSipHasher CConnman::GetDeterministicRandomizer(uint64_t id) const
{
return CSipHasher(nSeed0, nSeed1).Write(id);
}
-uint64_t CConnman::CalculateKeyedNetGroup(const CAddress& ad)
+uint64_t CConnman::CalculateKeyedNetGroup(const CAddress& ad) const
{
std::vector<unsigned char> vchNetGroup(ad.GetGroup());
- return GetDeterministicRandomizer(RANDOMIZER_ID_NETGROUP).Write(&vchNetGroup[0], vchNetGroup.size()).Finalize();
+ return GetDeterministicRandomizer(RANDOMIZER_ID_NETGROUP).Write(vchNetGroup.data(), vchNetGroup.size()).Finalize();
}
diff --git a/src/net.h b/src/net.h
index a9da38146b..905d6eb956 100644
--- a/src/net.h
+++ b/src/net.h
@@ -14,6 +14,7 @@
#include "hash.h"
#include "limitedmap.h"
#include "netaddress.h"
+#include "policy/feerate.h"
#include "protocol.h"
#include "random.h"
#include "streams.h"
@@ -32,11 +33,7 @@
#include <arpa/inet.h>
#endif
-#include <boost/filesystem/path.hpp>
-#include <boost/foreach.hpp>
-#include <boost/signals2/signal.hpp>
-class CAddrMan;
class CScheduler;
class CNode;
@@ -92,7 +89,7 @@ static const ServiceFlags REQUIRED_SERVICES = NODE_NETWORK;
// NOTE: When adjusting this, update rpcnet:setban's help ("24h")
static const unsigned int DEFAULT_MISBEHAVING_BANTIME = 60 * 60 * 24; // Default 24-hour ban
-typedef int NodeId;
+typedef int64_t NodeId;
struct AddedNodeInfo
{
@@ -102,7 +99,6 @@ struct AddedNodeInfo
bool fInbound;
};
-class CTransaction;
class CNodeStats;
class CClientUIInterface;
@@ -119,7 +115,7 @@ struct CSerializedNetMsg
std::string command;
};
-
+class NetEventsInterface;
class CConnman
{
public:
@@ -141,20 +137,45 @@ public:
int nMaxFeeler = 0;
int nBestHeight = 0;
CClientUIInterface* uiInterface = nullptr;
+ NetEventsInterface* m_msgproc = nullptr;
unsigned int nSendBufferMaxSize = 0;
unsigned int nReceiveFloodSize = 0;
uint64_t nMaxOutboundTimeframe = 0;
uint64_t nMaxOutboundLimit = 0;
+ std::vector<std::string> vSeedNodes;
+ std::vector<CSubNet> vWhitelistedRange;
+ std::vector<CService> vBinds, vWhiteBinds;
+ bool m_use_addrman_outgoing = true;
+ std::vector<std::string> m_specified_outgoing;
+ std::vector<std::string> m_added_nodes;
};
+
+ void Init(const Options& connOptions) {
+ nLocalServices = connOptions.nLocalServices;
+ nRelevantServices = connOptions.nRelevantServices;
+ nMaxConnections = connOptions.nMaxConnections;
+ nMaxOutbound = std::min(connOptions.nMaxOutbound, connOptions.nMaxConnections);
+ nMaxAddnode = connOptions.nMaxAddnode;
+ nMaxFeeler = connOptions.nMaxFeeler;
+ nBestHeight = connOptions.nBestHeight;
+ clientInterface = connOptions.uiInterface;
+ m_msgproc = connOptions.m_msgproc;
+ nSendBufferMaxSize = connOptions.nSendBufferMaxSize;
+ nReceiveFloodSize = connOptions.nReceiveFloodSize;
+ nMaxOutboundTimeframe = connOptions.nMaxOutboundTimeframe;
+ nMaxOutboundLimit = connOptions.nMaxOutboundLimit;
+ vWhitelistedRange = connOptions.vWhitelistedRange;
+ vAddedNodes = connOptions.m_added_nodes;
+ }
+
CConnman(uint64_t seed0, uint64_t seed1);
~CConnman();
- bool Start(CScheduler& scheduler, std::string& strNodeError, Options options);
+ bool Start(CScheduler& scheduler, const Options& options);
void Stop();
void Interrupt();
- bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
bool GetNetworkActive() const { return fNetworkActive; };
void SetNetworkActive(bool active);
- bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false, bool fAddnode = false);
+ bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = nullptr, const char *strDest = nullptr, bool fOneShot = false, bool fFeeler = false, bool fAddnode = false);
bool CheckIncomingNonce(uint64_t nonce);
bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func);
@@ -162,75 +183,33 @@ public:
void PushMessage(CNode* pnode, CSerializedNetMsg&& msg);
template<typename Callable>
- bool ForEachNodeContinueIf(Callable&& func)
- {
- LOCK(cs_vNodes);
- for (auto&& node : vNodes)
- if(!func(node))
- return false;
- return true;
- };
-
- template<typename Callable>
- bool ForEachNodeContinueIf(Callable&& func) const
- {
- LOCK(cs_vNodes);
- for (const auto& node : vNodes)
- if(!func(node))
- return false;
- return true;
- };
-
- template<typename Callable, typename CallableAfter>
- bool ForEachNodeContinueIfThen(Callable&& pre, CallableAfter&& post)
- {
- bool ret = true;
- LOCK(cs_vNodes);
- for (auto&& node : vNodes)
- if(!pre(node)) {
- ret = false;
- break;
- }
- post();
- return ret;
- };
-
- template<typename Callable, typename CallableAfter>
- bool ForEachNodeContinueIfThen(Callable&& pre, CallableAfter&& post) const
- {
- bool ret = true;
- LOCK(cs_vNodes);
- for (const auto& node : vNodes)
- if(!pre(node)) {
- ret = false;
- break;
- }
- post();
- return ret;
- };
-
- template<typename Callable>
void ForEachNode(Callable&& func)
{
LOCK(cs_vNodes);
- for (auto&& node : vNodes)
- func(node);
+ for (auto&& node : vNodes) {
+ if (NodeFullyConnected(node))
+ func(node);
+ }
};
template<typename Callable>
void ForEachNode(Callable&& func) const
{
LOCK(cs_vNodes);
- for (const auto& node : vNodes)
- func(node);
+ for (auto&& node : vNodes) {
+ if (NodeFullyConnected(node))
+ func(node);
+ }
};
template<typename Callable, typename CallableAfter>
void ForEachNodeThen(Callable&& pre, CallableAfter&& post)
{
LOCK(cs_vNodes);
- for (auto&& node : vNodes)
- pre(node);
+ for (auto&& node : vNodes) {
+ if (NodeFullyConnected(node))
+ pre(node);
+ }
post();
};
@@ -238,21 +217,19 @@ public:
void ForEachNodeThen(Callable&& pre, CallableAfter&& post) const
{
LOCK(cs_vNodes);
- for (const auto& node : vNodes)
- pre(node);
+ for (auto&& node : vNodes) {
+ if (NodeFullyConnected(node))
+ pre(node);
+ }
post();
};
- void RelayTransaction(const CTransaction& tx);
-
// Addrman functions
size_t GetAddressCount() const;
void SetServices(const CService &addr, ServiceFlags nServices);
void MarkAddressGood(const CAddress& addr);
- void AddNewAddress(const CAddress& addr, const CAddress& addrFrom, int64_t nTimePenalty = 0);
void AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty = 0);
std::vector<CAddress> GetAddresses();
- void AddressCurrentlyConnected(const CService& addr);
// Denial-of-service detection/prevention
// The idea is to detect peers that are behaving
@@ -278,22 +255,14 @@ public:
void GetBanned(banmap_t &banmap);
void SetBanned(const banmap_t &banmap);
- void AddOneShot(const std::string& strDest);
-
bool AddNode(const std::string& node);
bool RemoveAddedNode(const std::string& node);
std::vector<AddedNodeInfo> GetAddedNodeInfo();
size_t GetNodeCount(NumConnections num);
void GetNodeStats(std::vector<CNodeStats>& vstats);
- bool DisconnectAddress(const CNetAddr& addr);
bool DisconnectNode(const std::string& node);
bool DisconnectNode(NodeId id);
- bool DisconnectSubnet(const CSubNet& subnet);
-
- unsigned int GetSendBufferSize() const;
-
- void AddWhitelistedRange(const CSubNet &subnet);
ServiceFlags GetLocalServices() const;
@@ -325,7 +294,7 @@ public:
int GetBestHeight() const;
/** Get a unique deterministic randomizer. */
- CSipHasher GetDeterministicRandomizer(uint64_t id);
+ CSipHasher GetDeterministicRandomizer(uint64_t id) const;
unsigned int GetReceiveFloodSize() const;
@@ -338,15 +307,19 @@ private:
ListenSocket(SOCKET socket_, bool whitelisted_) : socket(socket_), whitelisted(whitelisted_) {}
};
+ bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
+ bool Bind(const CService &addr, unsigned int flags);
+ bool InitBinds(const std::vector<CService>& binds, const std::vector<CService>& whiteBinds);
void ThreadOpenAddedConnections();
+ void AddOneShot(const std::string& strDest);
void ProcessOneShot();
- void ThreadOpenConnections();
+ void ThreadOpenConnections(std::vector<std::string> connect);
void ThreadMessageHandler();
void AcceptConnection(const ListenSocket& hListenSocket);
void ThreadSocketHandler();
void ThreadDNSAddressSeed();
- uint64_t CalculateKeyedNetGroup(const CAddress& ad);
+ uint64_t CalculateKeyedNetGroup(const CAddress& ad) const;
CNode* FindNode(const CNetAddr& ip);
CNode* FindNode(const CSubNet& subNet);
@@ -361,7 +334,7 @@ private:
NodeId GetNewNodeId();
- size_t SocketSendData(CNode *pnode);
+ size_t SocketSendData(CNode *pnode) const;
//!check is the banlist has unwritten changes
bool BannedSetIsDirty();
//!set the "dirty" flag for the banlist
@@ -376,6 +349,9 @@ private:
void RecordBytesRecv(uint64_t bytes);
void RecordBytesSent(uint64_t bytes);
+ // Whether the node should be passed out in ForEach* callbacks
+ static bool NodeFullyConnected(const CNode* pnode);
+
// Network usage totals
CCriticalSection cs_totalBytesRecv;
CCriticalSection cs_totalBytesSent;
@@ -391,7 +367,6 @@ private:
// Whitelisted ranges. Any node connecting from these is automatically
// whitelisted (as well as those connecting to whitelisted binds).
std::vector<CSubNet> vWhitelistedRange;
- CCriticalSection cs_vWhitelistedRange;
unsigned int nSendBufferMaxSize;
unsigned int nReceiveFloodSize;
@@ -426,6 +401,7 @@ private:
int nMaxFeeler;
std::atomic<int> nBestHeight;
CClientUIInterface* clientInterface;
+ NetEventsInterface* m_msgproc;
/** SipHasher seeds for deterministic randomness */
const uint64_t nSeed0, nSeed1;
@@ -466,19 +442,18 @@ struct CombinerAll
}
};
-// Signals for message handling
-struct CNodeSignals
+/**
+ * Interface for message handling
+ */
+class NetEventsInterface
{
- boost::signals2::signal<bool (CNode*, CConnman&, std::atomic<bool>&), CombinerAll> ProcessMessages;
- boost::signals2::signal<bool (CNode*, CConnman&, std::atomic<bool>&), CombinerAll> SendMessages;
- boost::signals2::signal<void (CNode*, CConnman&)> InitializeNode;
- boost::signals2::signal<void (NodeId, bool&)> FinalizeNode;
+public:
+ virtual bool ProcessMessages(CNode* pnode, std::atomic<bool>& interrupt) = 0;
+ virtual bool SendMessages(CNode* pnode, std::atomic<bool>& interrupt) = 0;
+ virtual void InitializeNode(CNode* pnode) = 0;
+ virtual void FinalizeNode(NodeId id, bool& update_connection_time) = 0;
};
-
-CNodeSignals& GetNodeSignals();
-
-
enum
{
LOCAL_NONE, // unknown
@@ -500,7 +475,7 @@ bool AddLocal(const CNetAddr& addr, int nScore = LOCAL_NONE);
bool RemoveLocal(const CService& addr);
bool SeenLocal(const CService& addr);
bool IsLocal(const CService& addr);
-bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL);
+bool GetLocal(CService &addr, const CNetAddr *paddrPeer = nullptr);
bool IsReachable(enum Network net);
bool IsReachable(const CNetAddr &addr);
CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices);
@@ -548,8 +523,12 @@ public:
double dPingTime;
double dPingWait;
double dMinPing;
+ // Our address, as reported by the peer
std::string addrLocal;
+ // Address of this peer
CAddress addr;
+ // Bind address of our side of the connection
+ CAddress addrBind;
};
@@ -605,7 +584,7 @@ class CNode
friend class CConnman;
public:
// socket
- ServiceFlags nServices;
+ std::atomic<ServiceFlags> nServices;
ServiceFlags nServicesExpected;
SOCKET hSocket;
size_t nSendSize; // total size of all vSendMsg entries
@@ -613,35 +592,41 @@ public:
uint64_t nSendBytes;
std::deque<std::vector<unsigned char>> vSendMsg;
CCriticalSection cs_vSend;
+ CCriticalSection cs_hSocket;
+ CCriticalSection cs_vRecv;
CCriticalSection cs_vProcessMsg;
std::list<CNetMessage> vProcessMsg;
size_t nProcessQueueSize;
+ CCriticalSection cs_sendProcessing;
+
std::deque<CInv> vRecvGetData;
uint64_t nRecvBytes;
std::atomic<int> nRecvVersion;
- int64_t nLastSend;
- int64_t nLastRecv;
- int64_t nTimeConnected;
- int64_t nTimeOffset;
+ std::atomic<int64_t> nLastSend;
+ std::atomic<int64_t> nLastRecv;
+ const int64_t nTimeConnected;
+ std::atomic<int64_t> nTimeOffset;
+ // Address of this peer
const CAddress addr;
- std::string addrName;
- CService addrLocal;
- int nVersion;
+ // Bind address of our side of the connection
+ const CAddress addrBind;
+ std::atomic<int> nVersion;
// strSubVer is whatever byte array we read from the wire. However, this field is intended
// to be printed out, displayed to humans in various forms and so on. So we sanitize it and
// store the sanitized version in cleanSubVer. The original should be used when dealing with
// the network or wire types and the cleaned string used when displayed or logged.
std::string strSubVer, cleanSubVer;
+ CCriticalSection cs_SubVer; // used for both cleanSubVer and strSubVer
bool fWhitelisted; // This peer can bypass DoS banning.
bool fFeeler; // If true this node is being used as a short lived feeler.
bool fOneShot;
bool fAddnode;
bool fClient;
const bool fInbound;
- bool fSuccessfullyConnected;
+ std::atomic_bool fSuccessfullyConnected;
std::atomic_bool fDisconnect;
// We use fRelayTxes for two purposes -
// a) it allows us to not relay tx invs before receiving the peer's version message
@@ -652,8 +637,7 @@ public:
CSemaphoreGrant grantOutbound;
CCriticalSection cs_filter;
CBloomFilter* pfilter;
- int nRefCount;
- const NodeId id;
+ std::atomic<int> nRefCount;
const uint64_t nKeyedNetGroup;
std::atomic_bool fPauseRecv;
@@ -665,7 +649,7 @@ protected:
public:
uint256 hashContinue;
- int nStartingHeight;
+ std::atomic<int> nStartingHeight;
// flood relay
std::vector<CAddress> vAddrToSend;
@@ -703,50 +687,56 @@ public:
// Ping time measurement:
// The pong reply we're expecting, or 0 if no pong expected.
- uint64_t nPingNonceSent;
+ std::atomic<uint64_t> nPingNonceSent;
// Time (in usec) the last ping was sent, or 0 if no ping was ever sent.
- int64_t nPingUsecStart;
+ std::atomic<int64_t> nPingUsecStart;
// Last measured round-trip time.
- int64_t nPingUsecTime;
+ std::atomic<int64_t> nPingUsecTime;
// Best measured round-trip time.
- int64_t nMinPingUsecTime;
+ std::atomic<int64_t> nMinPingUsecTime;
// Whether a ping is requested.
- bool fPingQueued;
+ std::atomic<bool> fPingQueued;
// Minimum fee rate with which to filter inv's to this node
CAmount minFeeFilter;
CCriticalSection cs_feeFilter;
CAmount lastSentFeeFilter;
int64_t nextSendTimeFeeFilter;
- CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const std::string &addrNameIn = "", bool fInboundIn = false);
+ CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress &addrBindIn, const std::string &addrNameIn = "", bool fInboundIn = false);
~CNode();
+ CNode(const CNode&) = delete;
+ CNode& operator=(const CNode&) = delete;
private:
- CNode(const CNode&);
- void operator=(const CNode&);
-
-
+ const NodeId id;
const uint64_t nLocalHostNonce;
// Services offered to this peer
const ServiceFlags nLocalServices;
const int nMyStartingHeight;
int nSendVersion;
std::list<CNetMessage> vRecvMsg; // Used only by SocketHandler thread
+
+ mutable CCriticalSection cs_addrName;
+ std::string addrName;
+
+ // Our address, as reported by the peer
+ CService addrLocal;
+ mutable CCriticalSection cs_addrLocal;
public:
NodeId GetId() const {
- return id;
+ return id;
}
uint64_t GetLocalNonce() const {
- return nLocalHostNonce;
+ return nLocalHostNonce;
}
int GetMyStartingHeight() const {
- return nMyStartingHeight;
+ return nMyStartingHeight;
}
- int GetRefCount()
+ int GetRefCount() const
{
assert(nRefCount >= 0);
return nRefCount;
@@ -758,29 +748,16 @@ public:
{
nRecvVersion = nVersionIn;
}
- int GetRecvVersion()
+ int GetRecvVersion() const
{
return nRecvVersion;
}
- void SetSendVersion(int nVersionIn)
- {
- // Send version may only be changed in the version message, and
- // only one version message is allowed per session. We can therefore
- // treat this value as const and even atomic as long as it's only used
- // once the handshake is complete. Any attempt to set this twice is an
- // error.
- assert(nSendVersion == 0);
- nSendVersion = nVersionIn;
- }
+ void SetSendVersion(int nVersionIn);
+ int GetSendVersion() const;
- int GetSendVersion() const
- {
- // The send version should always be explicitly set to
- // INIT_PROTO_VERSION rather than using this value until the handshake
- // is complete.
- assert(nSendVersion != 0);
- return nSendVersion;
- }
+ CService GetAddrLocal() const;
+ //! May not be called more than once
+ void SetAddrLocal(const CService& addrLocalIn);
CNode* AddRef()
{
@@ -807,7 +784,7 @@ public:
// after addresses were pushed.
if (_addr.IsValid() && !addrKnown.contains(_addr.GetKey())) {
if (vAddrToSend.size() >= MAX_ADDR_TO_SEND) {
- vAddrToSend[insecure_rand.rand32() % vAddrToSend.size()] = _addr;
+ vAddrToSend[insecure_rand.randrange(vAddrToSend.size())] = _addr;
} else {
vAddrToSend.push_back(_addr);
}
@@ -851,6 +828,10 @@ public:
{
return nLocalServices;
}
+
+ std::string GetAddrName() const;
+ //! Sets the addrName only if it was not previously set
+ void MaybeSetAddrName(const std::string& addrNameIn);
};
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 03568283fb..7fced41d4f 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -22,6 +22,7 @@
#include "primitives/block.h"
#include "primitives/transaction.h"
#include "random.h"
+#include "reverse_iterator.h"
#include "tinyformat.h"
#include "txmempool.h"
#include "ui_interface.h"
@@ -30,15 +31,11 @@
#include "utilstrencodings.h"
#include "validationinterface.h"
-#include <boost/thread.hpp>
-
-using namespace std;
-
#if defined(NDEBUG)
# error "Bitcoin cannot be compiled without assertions."
#endif
-int64_t nTimeBestReceived = 0; // Used only to inform the wallet of when we last received a block
+std::atomic<int64_t> nTimeBestReceived(0); // Used only to inform the wallet of when we last received a block
struct IteratorComparator
{
@@ -55,10 +52,13 @@ struct COrphanTx {
NodeId fromPeer;
int64_t nTimeExpire;
};
-map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(cs_main);
-map<COutPoint, set<map<uint256, COrphanTx>::iterator, IteratorComparator>> mapOrphanTransactionsByPrev GUARDED_BY(cs_main);
+std::map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(cs_main);
+std::map<COutPoint, std::set<std::map<uint256, COrphanTx>::iterator, IteratorComparator>> mapOrphanTransactionsByPrev GUARDED_BY(cs_main);
void EraseOrphansFor(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+static size_t vExtraTxnForCompactIt = 0;
+static std::vector<std::pair<uint256, CTransactionRef>> vExtraTxnForCompact GUARDED_BY(cs_main);
+
static const uint64_t RANDOMIZER_ID_ADDRESS_RELAY = 0x3cac0035b5866b90ULL; // SHA256("main address relay")[0:8]
// Internal stuff
@@ -73,7 +73,7 @@ namespace {
* Set mapBlockSource[hash].second to false if the node should not be
* punished if the block is invalid.
*/
- map<uint256, std::pair<NodeId, bool>> mapBlockSource;
+ std::map<uint256, std::pair<NodeId, bool>> mapBlockSource;
/**
* Filter for transactions that were recently rejected by
@@ -105,10 +105,10 @@ namespace {
bool fValidatedHeaders; //!< Whether this block has validated headers at the time of request.
std::unique_ptr<PartiallyDownloadedBlock> partialBlock; //!< Optional, used for CMPCTBLOCK downloads
};
- map<uint256, pair<NodeId, list<QueuedBlock>::iterator> > mapBlocksInFlight;
+ std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> > mapBlocksInFlight;
/** Stack of nodes which we have set to announce using compact blocks */
- list<NodeId> lNodesAnnouncingHeaderAndIDs;
+ std::list<NodeId> lNodesAnnouncingHeaderAndIDs;
/** Number of preferable block download peers. */
int nPreferredDownload = 0;
@@ -121,18 +121,13 @@ namespace {
MapRelay mapRelay;
/** Expiration-time ordered list of (expire time, relay map entry) pairs, protected by cs_main). */
std::deque<std::pair<int64_t, MapRelay::iterator>> vRelayExpiration;
-} // anon namespace
-
-//////////////////////////////////////////////////////////////////////////////
-//
-// Registration of network node signals.
-//
+} // namespace
namespace {
struct CBlockReject {
unsigned char chRejectCode;
- string strRejectReason;
+ std::string strRejectReason;
uint256 hashBlock;
};
@@ -167,9 +162,11 @@ struct CNodeState {
int nUnconnectingHeaders;
//! Whether we've started headers synchronization with this peer.
bool fSyncStarted;
+ //! When to potentially disconnect peer for stalling headers download
+ int64_t nHeadersSyncTimeout;
//! Since when we're stalling block download progress (in microseconds), or 0.
int64_t nStallingSince;
- list<QueuedBlock> vBlocksInFlight;
+ std::list<QueuedBlock> vBlocksInFlight;
//! When the first entry in vBlocksInFlight started downloading. Don't care when vBlocksInFlight is empty.
int64_t nDownloadingSince;
int nBlocksInFlight;
@@ -200,12 +197,13 @@ struct CNodeState {
fCurrentlyConnected = false;
nMisbehavior = 0;
fShouldBan = false;
- pindexBestKnownBlock = NULL;
+ pindexBestKnownBlock = nullptr;
hashLastUnknownBlock.SetNull();
- pindexLastCommonBlock = NULL;
- pindexBestHeaderSent = NULL;
+ pindexLastCommonBlock = nullptr;
+ pindexBestHeaderSent = nullptr;
nUnconnectingHeaders = 0;
fSyncStarted = false;
+ nHeadersSyncTimeout = 0;
nStallingSince = 0;
nDownloadingSince = 0;
nBlocksInFlight = 0;
@@ -221,13 +219,13 @@ struct CNodeState {
};
/** Map maintaining per-node state. Requires cs_main. */
-map<NodeId, CNodeState> mapNodeState;
+std::map<NodeId, CNodeState> mapNodeState;
// Requires cs_main.
CNodeState *State(NodeId pnode) {
- map<NodeId, CNodeState>::iterator it = mapNodeState.find(pnode);
+ std::map<NodeId, CNodeState>::iterator it = mapNodeState.find(pnode);
if (it == mapNodeState.end())
- return NULL;
+ return nullptr;
return &it->second;
}
@@ -241,7 +239,7 @@ void UpdatePreferredDownload(CNode* node, CNodeState* state)
nPreferredDownload += state->fPreferredDownload;
}
-void PushNodeVersion(CNode *pnode, CConnman& connman, int64_t nTime)
+void PushNodeVersion(CNode *pnode, CConnman* connman, int64_t nTime)
{
ServiceFlags nLocalNodeServices = pnode->GetLocalServices();
uint64_t nonce = pnode->GetLocalNonce();
@@ -252,54 +250,13 @@ void PushNodeVersion(CNode *pnode, CConnman& connman, int64_t nTime)
CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService(), addr.nServices));
CAddress addrMe = CAddress(CService(), nLocalNodeServices);
- connman.PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe,
+ connman->PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe,
nonce, strSubVersion, nNodeStartingHeight, ::fRelayTxes));
- if (fLogIPs)
- LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), addrYou.ToString(), nodeid);
- else
- LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), nodeid);
-}
-
-void InitializeNode(CNode *pnode, CConnman& connman) {
- CAddress addr = pnode->addr;
- std::string addrName = pnode->addrName;
- NodeId nodeid = pnode->GetId();
- {
- LOCK(cs_main);
- mapNodeState.emplace_hint(mapNodeState.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(addr, std::move(addrName)));
- }
- if(!pnode->fInbound)
- PushNodeVersion(pnode, connman, GetTime());
-}
-
-void FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) {
- fUpdateConnectionTime = false;
- LOCK(cs_main);
- CNodeState *state = State(nodeid);
-
- if (state->fSyncStarted)
- nSyncStarted--;
-
- if (state->nMisbehavior == 0 && state->fCurrentlyConnected) {
- fUpdateConnectionTime = true;
- }
-
- BOOST_FOREACH(const QueuedBlock& entry, state->vBlocksInFlight) {
- mapBlocksInFlight.erase(entry.hash);
- }
- EraseOrphansFor(nodeid);
- nPreferredDownload -= state->fPreferredDownload;
- nPeersWithValidatedDownloads -= (state->nBlocksInFlightValidHeaders != 0);
- assert(nPeersWithValidatedDownloads >= 0);
-
- mapNodeState.erase(nodeid);
-
- if (mapNodeState.empty()) {
- // Do a consistency check after the last peer is removed.
- assert(mapBlocksInFlight.empty());
- assert(nPreferredDownload == 0);
- assert(nPeersWithValidatedDownloads == 0);
+ if (fLogIPs) {
+ LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), addrYou.ToString(), nodeid);
+ } else {
+ LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), nodeid);
}
}
@@ -307,9 +264,10 @@ void FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) {
// Returns a bool indicating whether we requested this block.
// Also used if a block was /not/ received and timed out or started with another peer
bool MarkBlockAsReceived(const uint256& hash) {
- map<uint256, pair<NodeId, list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash);
+ std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash);
if (itInFlight != mapBlocksInFlight.end()) {
CNodeState *state = State(itInFlight->second.first);
+ assert(state != nullptr);
state->nBlocksInFlightValidHeaders -= itInFlight->second.second->fValidatedHeaders;
if (state->nBlocksInFlightValidHeaders == 0 && itInFlight->second.second->fValidatedHeaders) {
// Last validated block on the queue was received.
@@ -331,29 +289,31 @@ bool MarkBlockAsReceived(const uint256& hash) {
// Requires cs_main.
// returns false, still setting pit, if the block was already in flight from the same peer
// pit will only be valid as long as the same cs_main lock is being held
-bool MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Params& consensusParams, const CBlockIndex *pindex = NULL, list<QueuedBlock>::iterator **pit = NULL) {
+bool MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const CBlockIndex* pindex = nullptr, std::list<QueuedBlock>::iterator** pit = nullptr) {
CNodeState *state = State(nodeid);
- assert(state != NULL);
+ assert(state != nullptr);
// Short-circuit most stuff in case its from the same node
- map<uint256, pair<NodeId, list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash);
+ std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash);
if (itInFlight != mapBlocksInFlight.end() && itInFlight->second.first == nodeid) {
- *pit = &itInFlight->second.second;
+ if (pit) {
+ *pit = &itInFlight->second.second;
+ }
return false;
}
// Make sure it's not listed somewhere already.
MarkBlockAsReceived(hash);
- list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(),
- {hash, pindex, pindex != NULL, std::unique_ptr<PartiallyDownloadedBlock>(pit ? new PartiallyDownloadedBlock(&mempool) : NULL)});
+ std::list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(),
+ {hash, pindex, pindex != nullptr, std::unique_ptr<PartiallyDownloadedBlock>(pit ? new PartiallyDownloadedBlock(&mempool) : nullptr)});
state->nBlocksInFlight++;
state->nBlocksInFlightValidHeaders += it->fValidatedHeaders;
if (state->nBlocksInFlight == 1) {
// We're starting a block download (batch) from this peer.
state->nDownloadingSince = GetTimeMicros();
}
- if (state->nBlocksInFlightValidHeaders == 1 && pindex != NULL) {
+ if (state->nBlocksInFlightValidHeaders == 1 && pindex != nullptr) {
nPeersWithValidatedDownloads++;
}
itInFlight = mapBlocksInFlight.insert(std::make_pair(hash, std::make_pair(nodeid, it))).first;
@@ -365,12 +325,12 @@ bool MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Pa
/** Check whether the last unknown block a peer advertised is not yet known. */
void ProcessBlockAvailability(NodeId nodeid) {
CNodeState *state = State(nodeid);
- assert(state != NULL);
+ assert(state != nullptr);
if (!state->hashLastUnknownBlock.IsNull()) {
BlockMap::iterator itOld = mapBlockIndex.find(state->hashLastUnknownBlock);
if (itOld != mapBlockIndex.end() && itOld->second->nChainWork > 0) {
- if (state->pindexBestKnownBlock == NULL || itOld->second->nChainWork >= state->pindexBestKnownBlock->nChainWork)
+ if (state->pindexBestKnownBlock == nullptr || itOld->second->nChainWork >= state->pindexBestKnownBlock->nChainWork)
state->pindexBestKnownBlock = itOld->second;
state->hashLastUnknownBlock.SetNull();
}
@@ -380,14 +340,14 @@ void ProcessBlockAvailability(NodeId nodeid) {
/** Update tracking information about which blocks a peer is assumed to have. */
void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) {
CNodeState *state = State(nodeid);
- assert(state != NULL);
+ assert(state != nullptr);
ProcessBlockAvailability(nodeid);
BlockMap::iterator it = mapBlockIndex.find(hash);
if (it != mapBlockIndex.end() && it->second->nChainWork > 0) {
// An actually better block was announced.
- if (state->pindexBestKnownBlock == NULL || it->second->nChainWork >= state->pindexBestKnownBlock->nChainWork)
+ if (state->pindexBestKnownBlock == nullptr || it->second->nChainWork >= state->pindexBestKnownBlock->nChainWork)
state->pindexBestKnownBlock = it->second;
} else {
// An unknown block was announced; just assume that the latest one is the best one.
@@ -395,7 +355,7 @@ void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) {
}
}
-void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman& connman) {
+void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman* connman) {
AssertLockHeld(cs_main);
CNodeState* nodestate = State(nodeid);
if (!nodestate || !nodestate->fSupportsDesiredCmpctVersion) {
@@ -410,20 +370,20 @@ void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman& connman) {
return;
}
}
- connman.ForNode(nodeid, [&connman](CNode* pfrom){
+ connman->ForNode(nodeid, [connman](CNode* pfrom){
bool fAnnounceUsingCMPCTBLOCK = false;
uint64_t nCMPCTBLOCKVersion = (pfrom->GetLocalServices() & NODE_WITNESS) ? 2 : 1;
if (lNodesAnnouncingHeaderAndIDs.size() >= 3) {
// As per BIP152, we only get 3 of our peers to announce
// blocks using compact encodings.
- connman.ForNode(lNodesAnnouncingHeaderAndIDs.front(), [&connman, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion](CNode* pnodeStop){
- connman.PushMessage(pnodeStop, CNetMsgMaker(pnodeStop->GetSendVersion()).Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
+ connman->ForNode(lNodesAnnouncingHeaderAndIDs.front(), [connman, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion](CNode* pnodeStop){
+ connman->PushMessage(pnodeStop, CNetMsgMaker(pnodeStop->GetSendVersion()).Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
return true;
});
lNodesAnnouncingHeaderAndIDs.pop_front();
}
fAnnounceUsingCMPCTBLOCK = true;
- connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
+ connman->PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
lNodesAnnouncingHeaderAndIDs.push_back(pfrom->GetId());
return true;
});
@@ -446,25 +406,6 @@ bool PeerHasHeader(CNodeState *state, const CBlockIndex *pindex)
return false;
}
-/** Find the last common ancestor two blocks have.
- * Both pa and pb must be non-NULL. */
-const CBlockIndex* LastCommonAncestor(const CBlockIndex* pa, const CBlockIndex* pb) {
- if (pa->nHeight > pb->nHeight) {
- pa = pa->GetAncestor(pb->nHeight);
- } else if (pb->nHeight > pa->nHeight) {
- pb = pb->GetAncestor(pa->nHeight);
- }
-
- while (pa != pb && pa && pb) {
- pa = pa->pprev;
- pb = pb->pprev;
- }
-
- // Eventually all chain branches meet at the genesis block.
- assert(pa == pb);
- return pa;
-}
-
/** Update pindexLastCommonBlock and add not-in-flight missing successors to vBlocks, until it has
* at most count entries. */
void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, NodeId& nodeStaller, const Consensus::Params& consensusParams) {
@@ -473,17 +414,17 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<con
vBlocks.reserve(vBlocks.size() + count);
CNodeState *state = State(nodeid);
- assert(state != NULL);
+ assert(state != nullptr);
// Make sure pindexBestKnownBlock is up to date, we'll need it.
ProcessBlockAvailability(nodeid);
- if (state->pindexBestKnownBlock == NULL || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork) {
+ if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < nMinimumChainWork) {
// This peer has nothing interesting.
return;
}
- if (state->pindexLastCommonBlock == NULL) {
+ if (state->pindexLastCommonBlock == nullptr) {
// Bootstrap quickly by guessing a parent of our best tip is the forking point.
// Guessing wrong in either direction is not a problem.
state->pindexLastCommonBlock = chainActive[std::min(state->pindexBestKnownBlock->nHeight, chainActive.Height())];
@@ -519,7 +460,7 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<con
// are not yet downloaded and not in flight to vBlocks. In the mean time, update
// 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(const CBlockIndex* pindex, vToFetch) {
+ for (const CBlockIndex* pindex : vToFetch) {
if (!pindex->IsValid(BLOCK_VALID_TREE)) {
// We consider the chain that this peer is on invalid.
return;
@@ -553,44 +494,83 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<con
}
}
-} // anon namespace
+} // namespace
+
+void PeerLogicValidation::InitializeNode(CNode *pnode) {
+ CAddress addr = pnode->addr;
+ std::string addrName = pnode->GetAddrName();
+ NodeId nodeid = pnode->GetId();
+ {
+ LOCK(cs_main);
+ mapNodeState.emplace_hint(mapNodeState.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(addr, std::move(addrName)));
+ }
+ if(!pnode->fInbound)
+ PushNodeVersion(pnode, connman, GetTime());
+}
+
+void PeerLogicValidation::FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) {
+ fUpdateConnectionTime = false;
+ LOCK(cs_main);
+ CNodeState *state = State(nodeid);
+ assert(state != nullptr);
+
+ if (state->fSyncStarted)
+ nSyncStarted--;
+
+ if (state->nMisbehavior == 0 && state->fCurrentlyConnected) {
+ fUpdateConnectionTime = true;
+ }
+
+ for (const QueuedBlock& entry : state->vBlocksInFlight) {
+ mapBlocksInFlight.erase(entry.hash);
+ }
+ EraseOrphansFor(nodeid);
+ nPreferredDownload -= state->fPreferredDownload;
+ nPeersWithValidatedDownloads -= (state->nBlocksInFlightValidHeaders != 0);
+ assert(nPeersWithValidatedDownloads >= 0);
+
+ mapNodeState.erase(nodeid);
+
+ if (mapNodeState.empty()) {
+ // Do a consistency check after the last peer is removed.
+ assert(mapBlocksInFlight.empty());
+ assert(nPreferredDownload == 0);
+ assert(nPeersWithValidatedDownloads == 0);
+ }
+ LogPrint(BCLog::NET, "Cleared nodestate for peer=%d\n", nodeid);
+}
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
LOCK(cs_main);
CNodeState *state = State(nodeid);
- if (state == NULL)
+ if (state == nullptr)
return false;
stats.nMisbehavior = state->nMisbehavior;
stats.nSyncHeight = state->pindexBestKnownBlock ? state->pindexBestKnownBlock->nHeight : -1;
stats.nCommonHeight = state->pindexLastCommonBlock ? state->pindexLastCommonBlock->nHeight : -1;
- BOOST_FOREACH(const QueuedBlock& queue, state->vBlocksInFlight) {
+ for (const QueuedBlock& queue : state->vBlocksInFlight) {
if (queue.pindex)
stats.vHeightInFlight.push_back(queue.pindex->nHeight);
}
return true;
}
-void RegisterNodeSignals(CNodeSignals& nodeSignals)
-{
- nodeSignals.ProcessMessages.connect(&ProcessMessages);
- nodeSignals.SendMessages.connect(&SendMessages);
- nodeSignals.InitializeNode.connect(&InitializeNode);
- nodeSignals.FinalizeNode.connect(&FinalizeNode);
-}
-
-void UnregisterNodeSignals(CNodeSignals& nodeSignals)
-{
- nodeSignals.ProcessMessages.disconnect(&ProcessMessages);
- nodeSignals.SendMessages.disconnect(&SendMessages);
- nodeSignals.InitializeNode.disconnect(&InitializeNode);
- nodeSignals.FinalizeNode.disconnect(&FinalizeNode);
-}
-
//////////////////////////////////////////////////////////////////////////////
//
// mapOrphanTransactions
//
+void AddToCompactExtraTransactions(const CTransactionRef& tx)
+{
+ size_t max_extra_txn = gArgs.GetArg("-blockreconstructionextratxn", DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN);
+ if (max_extra_txn <= 0)
+ return;
+ if (!vExtraTxnForCompact.size())
+ vExtraTxnForCompact.resize(max_extra_txn);
+ vExtraTxnForCompact[vExtraTxnForCompactIt] = std::make_pair(tx->GetWitnessHash(), tx);
+ vExtraTxnForCompactIt = (vExtraTxnForCompactIt + 1) % max_extra_txn;
+}
+
bool AddOrphanTx(const CTransactionRef& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
const uint256& hash = tx->GetHash();
@@ -607,27 +587,29 @@ bool AddOrphanTx(const CTransactionRef& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRE
unsigned int sz = GetTransactionWeight(*tx);
if (sz >= MAX_STANDARD_TX_WEIGHT)
{
- LogPrint("mempool", "ignoring large orphan tx (size: %u, hash: %s)\n", sz, hash.ToString());
+ LogPrint(BCLog::MEMPOOL, "ignoring large orphan tx (size: %u, hash: %s)\n", sz, hash.ToString());
return false;
}
auto ret = mapOrphanTransactions.emplace(hash, COrphanTx{tx, peer, GetTime() + ORPHAN_TX_EXPIRE_TIME});
assert(ret.second);
- BOOST_FOREACH(const CTxIn& txin, tx->vin) {
+ for (const CTxIn& txin : tx->vin) {
mapOrphanTransactionsByPrev[txin.prevout].insert(ret.first);
}
- LogPrint("mempool", "stored orphan tx %s (mapsz %u outsz %u)\n", hash.ToString(),
+ AddToCompactExtraTransactions(tx);
+
+ LogPrint(BCLog::MEMPOOL, "stored orphan tx %s (mapsz %u outsz %u)\n", hash.ToString(),
mapOrphanTransactions.size(), mapOrphanTransactionsByPrev.size());
return true;
}
int static EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
- map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.find(hash);
+ std::map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.find(hash);
if (it == mapOrphanTransactions.end())
return 0;
- BOOST_FOREACH(const CTxIn& txin, it->second.tx->vin)
+ for (const CTxIn& txin : it->second.tx->vin)
{
auto itPrev = mapOrphanTransactionsByPrev.find(txin.prevout);
if (itPrev == mapOrphanTransactionsByPrev.end())
@@ -643,16 +625,16 @@ int static EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
void EraseOrphansFor(NodeId peer)
{
int nErased = 0;
- map<uint256, COrphanTx>::iterator iter = mapOrphanTransactions.begin();
+ std::map<uint256, COrphanTx>::iterator iter = mapOrphanTransactions.begin();
while (iter != mapOrphanTransactions.end())
{
- map<uint256, COrphanTx>::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid
+ std::map<uint256, COrphanTx>::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid
if (maybeErase->second.fromPeer == peer)
{
nErased += EraseOrphanTx(maybeErase->second.tx->GetHash());
}
}
- if (nErased > 0) LogPrint("mempool", "Erased %d orphan tx from peer=%d\n", nErased, peer);
+ if (nErased > 0) LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx from peer=%d\n", nErased, peer);
}
@@ -665,10 +647,10 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRE
// Sweep out expired orphan pool entries:
int nErased = 0;
int64_t nMinExpTime = nNow + ORPHAN_TX_EXPIRE_TIME - ORPHAN_TX_EXPIRE_INTERVAL;
- map<uint256, COrphanTx>::iterator iter = mapOrphanTransactions.begin();
+ std::map<uint256, COrphanTx>::iterator iter = mapOrphanTransactions.begin();
while (iter != mapOrphanTransactions.end())
{
- map<uint256, COrphanTx>::iterator maybeErase = iter++;
+ std::map<uint256, COrphanTx>::iterator maybeErase = iter++;
if (maybeErase->second.nTimeExpire <= nNow) {
nErased += EraseOrphanTx(maybeErase->second.tx->GetHash());
} else {
@@ -677,13 +659,13 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRE
}
// Sweep again 5 minutes after the next entry that expires in order to batch the linear scan.
nNextSweep = nMinExpTime + ORPHAN_TX_EXPIRE_INTERVAL;
- if (nErased > 0) LogPrint("mempool", "Erased %d orphan tx due to expiration\n", nErased);
+ if (nErased > 0) LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx due to expiration\n", nErased);
}
while (mapOrphanTransactions.size() > nMaxOrphans)
{
// Evict a random orphan:
uint256 randomhash = GetRandHash();
- map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.lower_bound(randomhash);
+ std::map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.lower_bound(randomhash);
if (it == mapOrphanTransactions.end())
it = mapOrphanTransactions.begin();
EraseOrphanTx(it->first);
@@ -699,11 +681,11 @@ void Misbehaving(NodeId pnode, int howmuch)
return;
CNodeState *state = State(pnode);
- if (state == NULL)
+ if (state == nullptr)
return;
state->nMisbehavior += howmuch;
- int banscore = GetArg("-banscore", DEFAULT_BANSCORE_THRESHOLD);
+ int banscore = gArgs.GetArg("-banscore", DEFAULT_BANSCORE_THRESHOLD);
if (state->nMisbehavior >= banscore && state->nMisbehavior - howmuch < banscore)
{
LogPrintf("%s: %s peer=%d (%d -> %d) BAN THRESHOLD EXCEEDED\n", __func__, state->name, pnode, state->nMisbehavior-howmuch, state->nMisbehavior);
@@ -729,42 +711,46 @@ PeerLogicValidation::PeerLogicValidation(CConnman* connmanIn) : connman(connmanI
recentRejects.reset(new CRollingBloomFilter(120000, 0.000001));
}
-void PeerLogicValidation::SyncTransaction(const CTransaction& tx, const CBlockIndex* pindex, int nPosInBlock) {
- if (nPosInBlock == CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK)
- return;
-
+void PeerLogicValidation::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex, const std::vector<CTransactionRef>& vtxConflicted) {
LOCK(cs_main);
std::vector<uint256> vOrphanErase;
- // Which orphan pool entries must we evict?
- for (size_t j = 0; j < tx.vin.size(); j++) {
- auto itByPrev = mapOrphanTransactionsByPrev.find(tx.vin[j].prevout);
- if (itByPrev == mapOrphanTransactionsByPrev.end()) continue;
- for (auto mi = itByPrev->second.begin(); mi != itByPrev->second.end(); ++mi) {
- const CTransaction& orphanTx = *(*mi)->second.tx;
- const uint256& orphanHash = orphanTx.GetHash();
- vOrphanErase.push_back(orphanHash);
+
+ for (const CTransactionRef& ptx : pblock->vtx) {
+ const CTransaction& tx = *ptx;
+
+ // Which orphan pool entries must we evict?
+ for (const auto& txin : tx.vin) {
+ auto itByPrev = mapOrphanTransactionsByPrev.find(txin.prevout);
+ if (itByPrev == mapOrphanTransactionsByPrev.end()) continue;
+ for (auto mi = itByPrev->second.begin(); mi != itByPrev->second.end(); ++mi) {
+ const CTransaction& orphanTx = *(*mi)->second.tx;
+ const uint256& orphanHash = orphanTx.GetHash();
+ vOrphanErase.push_back(orphanHash);
+ }
}
}
// Erase orphan transactions include or precluded by this block
if (vOrphanErase.size()) {
int nErased = 0;
- BOOST_FOREACH(uint256 &orphanHash, vOrphanErase) {
+ for (uint256 &orphanHash : vOrphanErase) {
nErased += EraseOrphanTx(orphanHash);
}
- LogPrint("mempool", "Erased %d orphan tx included or conflicted by block\n", nErased);
+ LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx included or conflicted by block\n", nErased);
}
}
+// All of the following cache a recent block, and are protected by cs_most_recent_block
static CCriticalSection cs_most_recent_block;
static std::shared_ptr<const CBlock> most_recent_block;
static std::shared_ptr<const CBlockHeaderAndShortTxIDs> most_recent_compact_block;
static uint256 most_recent_block_hash;
+static bool fWitnessesPresentInMostRecentCompactBlock;
void PeerLogicValidation::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock) {
std::shared_ptr<const CBlockHeaderAndShortTxIDs> pcmpctblock = std::make_shared<const CBlockHeaderAndShortTxIDs> (*pblock, true);
- CNetMsgMaker msgMaker(PROTOCOL_VERSION);
+ const CNetMsgMaker msgMaker(PROTOCOL_VERSION);
LOCK(cs_main);
@@ -781,6 +767,7 @@ void PeerLogicValidation::NewPoWValidBlock(const CBlockIndex *pindex, const std:
most_recent_block_hash = hashBlock;
most_recent_block = pblock;
most_recent_compact_block = pcmpctblock;
+ fWitnessesPresentInMostRecentCompactBlock = fWitnessEnabled;
}
connman->ForEachNode([this, &pcmpctblock, pindex, &msgMaker, fWitnessEnabled, &hashBlock](CNode* pnode) {
@@ -794,8 +781,8 @@ void PeerLogicValidation::NewPoWValidBlock(const CBlockIndex *pindex, const std:
if (state.fPreferHeaderAndIDs && (!fWitnessEnabled || state.fWantsCmpctWitness) &&
!PeerHasHeader(&state, pindex) && PeerHasHeader(&state, pindex->pprev)) {
- LogPrint("net", "%s sending header-and-ids %s to peer=%d\n", "PeerLogicValidation::NewPoWValidBlock",
- hashBlock.ToString(), pnode->id);
+ LogPrint(BCLog::NET, "%s sending header-and-ids %s to peer=%d\n", "PeerLogicValidation::NewPoWValidBlock",
+ hashBlock.ToString(), pnode->GetId());
connman->PushMessage(pnode, msgMaker.Make(NetMsgType::CMPCTBLOCK, *pcmpctblock));
state.pindexBestHeaderSent = pindex;
}
@@ -822,7 +809,7 @@ void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CB
// Relay inventory, but don't relay old inventory during initial block download.
connman->ForEachNode([nNewHeight, &vHashes](CNode* pnode) {
if (nNewHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 0)) {
- BOOST_REVERSE_FOREACH(const uint256& hash, vHashes) {
+ for (const uint256& hash : reverse_iterate(vHashes)) {
pnode->PushBlockHash(hash);
}
}
@@ -841,17 +828,25 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationSta
int nDoS = 0;
if (state.IsInvalid(nDoS)) {
- if (it != mapBlockSource.end() && State(it->second.first)) {
- assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
+ // Don't send reject message with code 0 or an internal reject code.
+ if (it != mapBlockSource.end() && State(it->second.first) && state.GetRejectCode() > 0 && state.GetRejectCode() < REJECT_INTERNAL) {
CBlockReject reject = {(unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), hash};
State(it->second.first)->rejects.push_back(reject);
if (nDoS > 0 && it->second.second)
Misbehaving(it->second.first, nDoS);
}
}
- else if (state.IsValid() && !IsInitialBlockDownload() && mapBlocksInFlight.count(hash) == mapBlocksInFlight.size()) {
+ // Check that:
+ // 1. The block is valid
+ // 2. We're not in initial block download
+ // 3. This is currently the best block we're aware of. We haven't updated
+ // the tip yet so we have no way to check this directly here. Instead we
+ // just check that there are currently no other blocks in flight.
+ else if (state.IsValid() &&
+ !IsInitialBlockDownload() &&
+ mapBlocksInFlight.count(hash) == mapBlocksInFlight.size()) {
if (it != mapBlockSource.end()) {
- MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first, *connman);
+ MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first, connman);
}
}
if (it != mapBlockSource.end())
@@ -882,12 +877,11 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
recentRejects->reset();
}
- // Use pcoinsTip->HaveCoinsInCache as a quick approximation to exclude
- // requesting or processing some txs which have already been included in a block
return recentRejects->contains(inv.hash) ||
mempool.exists(inv.hash) ||
mapOrphanTransactions.count(inv.hash) ||
- pcoinsTip->HaveCoinsInCache(inv.hash);
+ pcoinsTip->HaveCoinInCache(COutPoint(inv.hash, 0)) || // Best effort: only try output 0 and 1
+ pcoinsTip->HaveCoinInCache(COutPoint(inv.hash, 1));
}
case MSG_BLOCK:
case MSG_WITNESS_BLOCK:
@@ -897,16 +891,16 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
return true;
}
-static void RelayTransaction(const CTransaction& tx, CConnman& connman)
+static void RelayTransaction(const CTransaction& tx, CConnman* connman)
{
CInv inv(MSG_TX, tx.GetHash());
- connman.ForEachNode([&inv](CNode* pnode)
+ connman->ForEachNode([&inv](CNode* pnode)
{
pnode->PushInventory(inv);
});
}
-static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connman)
+static void RelayAddress(const CAddress& addr, bool fReachable, CConnman* connman)
{
unsigned int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s)
@@ -914,7 +908,7 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connma
// Use deterministic randomness to send to the same nodes for 24 hours
// at a time so the addrKnowns of the chosen nodes prevent repeats
uint64_t hashAddr = addr.GetHash();
- const CSipHasher hasher = connman.GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60));
+ const CSipHasher hasher = connman->GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60));
FastRandomContext insecure_rand;
std::array<std::pair<uint64_t, CNode*>,2> best{{{0, nullptr}, {0, nullptr}}};
@@ -922,7 +916,7 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connma
auto sortfunc = [&best, &hasher, nRelayNodes](CNode* pnode) {
if (pnode->nVersion >= CADDR_TIME_VERSION) {
- uint64_t hashKey = CSipHasher(hasher).Write(pnode->id).Finalize();
+ uint64_t hashKey = CSipHasher(hasher).Write(pnode->GetId()).Finalize();
for (unsigned int i = 0; i < nRelayNodes; i++) {
if (hashKey > best[i].first) {
std::copy(best.begin() + i, best.begin() + nRelayNodes - 1, best.begin() + i + 1);
@@ -939,14 +933,14 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connma
}
};
- connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc));
+ connman->ForEachNodeThen(std::move(sortfunc), std::move(pushfunc));
}
-void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams, CConnman& connman, std::atomic<bool>& interruptMsgProc)
+void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams, CConnman* connman, const std::atomic<bool>& interruptMsgProc)
{
std::deque<CInv>::iterator it = pfrom->vRecvGetData.begin();
- vector<CInv> vNotFound;
- CNetMsgMaker msgMaker(pfrom->GetSendVersion());
+ std::vector<CInv> vNotFound;
+ const CNetMsgMaker msgMaker(pfrom->GetSendVersion());
LOCK(cs_main);
while (it != pfrom->vRecvGetData.end()) {
@@ -965,6 +959,15 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
{
bool send = false;
BlockMap::iterator mi = mapBlockIndex.find(inv.hash);
+ std::shared_ptr<const CBlock> a_recent_block;
+ std::shared_ptr<const CBlockHeaderAndShortTxIDs> a_recent_compact_block;
+ bool fWitnessesPresentInARecentCompactBlock;
+ {
+ LOCK(cs_most_recent_block);
+ a_recent_block = most_recent_block;
+ a_recent_compact_block = most_recent_compact_block;
+ fWitnessesPresentInARecentCompactBlock = fWitnessesPresentInMostRecentCompactBlock;
+ }
if (mi != mapBlockIndex.end())
{
if (mi->second->nChainTx && !mi->second->IsValid(BLOCK_VALID_SCRIPTS) &&
@@ -974,11 +977,6 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// before ActivateBestChain but after AcceptBlock).
// In this case, we need to run ActivateBestChain prior to checking the relay
// conditions below.
- std::shared_ptr<const CBlock> a_recent_block;
- {
- LOCK(cs_most_recent_block);
- a_recent_block = most_recent_block;
- }
CValidationState dummy;
ActivateBestChain(dummy, Params(), a_recent_block);
}
@@ -989,7 +987,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// To prevent fingerprinting attacks, only send blocks outside of the active
// chain if they are valid, and no more than a month older (both in time, and in
// best equivalent proof of work) than the best header chain we know about.
- send = mi->second->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != NULL) &&
+ send = mi->second->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != nullptr) &&
(pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() < nOneMonth) &&
(GetBlockProofEquivalentTime(*pindexBestHeader, *mi->second, *pindexBestHeader, consensusParams) < nOneMonth);
if (!send) {
@@ -1000,9 +998,9 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// disconnect node in case we have reached the outbound limit for serving historical blocks
// never disconnect whitelisted nodes
static const int nOneWeek = 7 * 24 * 60 * 60; // assume > 1 week = historical
- if (send && connman.OutboundTargetReached(true) && ( ((pindexBestHeader != NULL) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted)
+ if (send && connman->OutboundTargetReached(true) && ( ((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted)
{
- LogPrint("net", "historical block serving limit reached, disconnect peer=%d\n", pfrom->GetId());
+ LogPrint(BCLog::NET, "historical block serving limit reached, disconnect peer=%d\n", pfrom->GetId());
//disconnect node
pfrom->fDisconnect = true;
@@ -1012,14 +1010,20 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// it's available before trying to send.
if (send && (mi->second->nStatus & BLOCK_HAVE_DATA))
{
- // Send block from disk
- CBlock block;
- if (!ReadBlockFromDisk(block, (*mi).second, consensusParams))
- assert(!"cannot load block from disk");
+ std::shared_ptr<const CBlock> pblock;
+ if (a_recent_block && a_recent_block->GetHash() == (*mi).second->GetBlockHash()) {
+ pblock = a_recent_block;
+ } else {
+ // Send block from disk
+ std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>();
+ if (!ReadBlockFromDisk(*pblockRead, (*mi).second, consensusParams))
+ assert(!"cannot load block from disk");
+ pblock = pblockRead;
+ }
if (inv.type == MSG_BLOCK)
- connman.PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, block));
+ connman->PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, *pblock));
else if (inv.type == MSG_WITNESS_BLOCK)
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::BLOCK, block));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::BLOCK, *pblock));
else if (inv.type == MSG_FILTERED_BLOCK)
{
bool sendMerkleBlock = false;
@@ -1028,11 +1032,11 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
LOCK(pfrom->cs_filter);
if (pfrom->pfilter) {
sendMerkleBlock = true;
- merkleBlock = CMerkleBlock(block, *pfrom->pfilter);
+ merkleBlock = CMerkleBlock(*pblock, *pfrom->pfilter);
}
}
if (sendMerkleBlock) {
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::MERKLEBLOCK, merkleBlock));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::MERKLEBLOCK, merkleBlock));
// CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see
// This avoids hurting performance by pointlessly requiring a round-trip
// Note that there is currently no way for a node to request any single transactions we didn't send here -
@@ -1040,8 +1044,8 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// Thus, the protocol spec specified allows for us to provide duplicate txn here,
// however we MUST always provide at least what the remote peer needs
typedef std::pair<unsigned int, uint256> PairType;
- BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn)
- connman.PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, *block.vtx[pair.first]));
+ for (PairType& pair : merkleBlock.vMatchedTxn)
+ connman->PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, *pblock->vtx[pair.first]));
}
// else
// no response
@@ -1055,10 +1059,15 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
bool fPeerWantsWitness = State(pfrom->GetId())->fWantsCmpctWitness;
int nSendFlags = fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS;
if (CanDirectFetch(consensusParams) && mi->second->nHeight >= chainActive.Height() - MAX_CMPCTBLOCK_DEPTH) {
- CBlockHeaderAndShortTxIDs cmpctblock(block, fPeerWantsWitness);
- connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));
- } else
- connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCK, block));
+ if ((fPeerWantsWitness || !fWitnessesPresentInARecentCompactBlock) && a_recent_compact_block && a_recent_compact_block->header.GetHash() == mi->second->GetBlockHash()) {
+ connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *a_recent_compact_block));
+ } else {
+ CBlockHeaderAndShortTxIDs cmpctblock(*pblock, fPeerWantsWitness);
+ connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));
+ }
+ } else {
+ connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCK, *pblock));
+ }
}
// Trigger the peer node to send a getblocks request for the next batch of inventory
@@ -1067,9 +1076,9 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// Bypass PushInventory, this must send even if redundant,
// and we want it right after the last block so they don't
// wait for other stuff first.
- vector<CInv> vInv;
+ std::vector<CInv> vInv;
vInv.push_back(CInv(MSG_BLOCK, chainActive.Tip()->GetBlockHash()));
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::INV, vInv));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::INV, vInv));
pfrom->hashContinue.SetNull();
}
}
@@ -1081,14 +1090,14 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
auto mi = mapRelay.find(inv.hash);
int nSendFlags = (inv.type == MSG_TX ? SERIALIZE_TRANSACTION_NO_WITNESS : 0);
if (mi != mapRelay.end()) {
- connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *mi->second));
+ connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *mi->second));
push = true;
} else if (pfrom->timeLastMempoolReq) {
auto txinfo = mempool.info(inv.hash);
// To protect privacy, do not answer getdata using the mempool when
// that TX couldn't have been INVed in reply to a MEMPOOL request.
if (txinfo.tx && txinfo.nTime <= pfrom->timeLastMempoolReq) {
- connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *txinfo.tx));
+ connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *txinfo.tx));
push = true;
}
}
@@ -1115,11 +1124,11 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// do that because they want to know about (and store and rebroadcast and
// risk analyze) the dependencies of transactions relevant to them, without
// having to download the entire memory pool.
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::NOTFOUND, vNotFound));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::NOTFOUND, vNotFound));
}
}
-uint32_t GetFetchFlags(CNode* pfrom, const CBlockIndex* pprev, const Consensus::Params& chainparams) {
+uint32_t GetFetchFlags(CNode* pfrom) {
uint32_t nFetchFlags = 0;
if ((pfrom->GetLocalServices() & NODE_WITNESS) && State(pfrom->GetId())->fHaveWitness) {
nFetchFlags |= MSG_WITNESS_FLAG;
@@ -1127,27 +1136,27 @@ uint32_t GetFetchFlags(CNode* pfrom, const CBlockIndex* pprev, const Consensus::
return nFetchFlags;
}
-inline void static SendBlockTransactions(const CBlock& block, const BlockTransactionsRequest& req, CNode* pfrom, CConnman& connman) {
+inline void static SendBlockTransactions(const CBlock& block, const BlockTransactionsRequest& req, CNode* pfrom, CConnman* connman) {
BlockTransactions resp(req);
for (size_t i = 0; i < req.indexes.size(); i++) {
if (req.indexes[i] >= block.vtx.size()) {
LOCK(cs_main);
Misbehaving(pfrom->GetId(), 100);
- LogPrintf("Peer %d sent us a getblocktxn with out-of-bounds tx indices", pfrom->id);
+ LogPrintf("Peer %d sent us a getblocktxn with out-of-bounds tx indices", pfrom->GetId());
return;
}
resp.txn[i] = block.vtx[req.indexes[i]];
}
LOCK(cs_main);
- CNetMsgMaker msgMaker(pfrom->GetSendVersion());
+ const CNetMsgMaker msgMaker(pfrom->GetSendVersion());
int nSendFlags = State(pfrom->GetId())->fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS;
- connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCKTXN, resp));
+ connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCKTXN, resp));
}
-bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman& connman, std::atomic<bool>& interruptMsgProc)
+bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman* connman, const std::atomic<bool>& interruptMsgProc)
{
- LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id);
- if (IsArgSet("-dropmessagestest") && GetRand(GetArg("-dropmessagestest", 0)) == 0)
+ LogPrint(BCLog::NET, "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->GetId());
+ if (gArgs.IsArgSet("-dropmessagestest") && GetRand(gArgs.GetArg("-dropmessagestest", 0)) == 0)
{
LogPrintf("dropmessagestest DROPPING RECV MESSAGE\n");
return true;
@@ -1168,13 +1177,36 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
}
+ if (strCommand == NetMsgType::REJECT)
+ {
+ if (LogAcceptCategory(BCLog::NET)) {
+ try {
+ std::string strMsg; unsigned char ccode; std::string strReason;
+ vRecv >> LIMITED_STRING(strMsg, CMessageHeader::COMMAND_SIZE) >> ccode >> LIMITED_STRING(strReason, MAX_REJECT_MESSAGE_LENGTH);
+
+ std::ostringstream ss;
+ ss << strMsg << " code " << itostr(ccode) << ": " << strReason;
- if (strCommand == NetMsgType::VERSION)
+ if (strMsg == NetMsgType::BLOCK || strMsg == NetMsgType::TX)
+ {
+ uint256 hash;
+ vRecv >> hash;
+ ss << ": hash " << hash.ToString();
+ }
+ LogPrint(BCLog::NET, "Reject %s\n", SanitizeString(ss.str()));
+ } catch (const std::ios_base::failure&) {
+ // Avoid feedback loops by preventing reject messages from triggering a new reject message.
+ LogPrint(BCLog::NET, "Unparseable reject message received\n");
+ }
+ }
+ }
+
+ else if (strCommand == NetMsgType::VERSION)
{
// Each connection can only send one version message
if (pfrom->nVersion != 0)
{
- connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, string("Duplicate version message")));
+ connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, std::string("Duplicate version message")));
LOCK(cs_main);
Misbehaving(pfrom->GetId(), 1);
return false;
@@ -1185,59 +1217,72 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
CAddress addrFrom;
uint64_t nNonce = 1;
uint64_t nServiceInt;
- vRecv >> pfrom->nVersion >> nServiceInt >> nTime >> addrMe;
- pfrom->nServices = ServiceFlags(nServiceInt);
+ ServiceFlags nServices;
+ int nVersion;
+ int nSendVersion;
+ std::string strSubVer;
+ std::string cleanSubVer;
+ int nStartingHeight = -1;
+ bool fRelay = true;
+
+ vRecv >> nVersion >> nServiceInt >> nTime >> addrMe;
+ nSendVersion = std::min(nVersion, PROTOCOL_VERSION);
+ nServices = ServiceFlags(nServiceInt);
if (!pfrom->fInbound)
{
- connman.SetServices(pfrom->addr, pfrom->nServices);
+ connman->SetServices(pfrom->addr, nServices);
}
- if (pfrom->nServicesExpected & ~pfrom->nServices)
+ if (pfrom->nServicesExpected & ~nServices)
{
- LogPrint("net", "peer=%d does not offer the expected services (%08x offered, %08x expected); disconnecting\n", pfrom->id, pfrom->nServices, pfrom->nServicesExpected);
- connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_NONSTANDARD,
+ LogPrint(BCLog::NET, "peer=%d does not offer the expected services (%08x offered, %08x expected); disconnecting\n", pfrom->GetId(), nServices, pfrom->nServicesExpected);
+ connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_NONSTANDARD,
strprintf("Expected to offer services %08x", pfrom->nServicesExpected)));
pfrom->fDisconnect = true;
return false;
}
- if (pfrom->nVersion < MIN_PEER_PROTO_VERSION)
+ if (nServices & ((1 << 7) | (1 << 5))) {
+ if (GetTime() < 1533096000) {
+ // Immediately disconnect peers that use service bits 6 or 8 until August 1st, 2018
+ // These bits have been used as a flag to indicate that a node is running incompatible
+ // consensus rules instead of changing the network magic, so we're stuck disconnecting
+ // based on these service bits, at least for a while.
+ pfrom->fDisconnect = true;
+ return false;
+ }
+ }
+
+ if (nVersion < MIN_PEER_PROTO_VERSION)
{
// disconnect from peers older than this proto version
- LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->id, pfrom->nVersion);
- connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE,
+ LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->GetId(), nVersion);
+ connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE,
strprintf("Version must be %d or greater", MIN_PEER_PROTO_VERSION)));
pfrom->fDisconnect = true;
return false;
}
- if (pfrom->nVersion == 10300)
- pfrom->nVersion = 300;
+ if (nVersion == 10300)
+ nVersion = 300;
if (!vRecv.empty())
vRecv >> addrFrom >> nNonce;
if (!vRecv.empty()) {
- vRecv >> LIMITED_STRING(pfrom->strSubVer, MAX_SUBVERSION_LENGTH);
- pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer);
+ vRecv >> LIMITED_STRING(strSubVer, MAX_SUBVERSION_LENGTH);
+ cleanSubVer = SanitizeString(strSubVer);
}
if (!vRecv.empty()) {
- vRecv >> pfrom->nStartingHeight;
+ vRecv >> nStartingHeight;
}
- {
- LOCK(pfrom->cs_filter);
- if (!vRecv.empty())
- vRecv >> pfrom->fRelayTxes; // set to true after we get the first filter* message
- else
- pfrom->fRelayTxes = true;
- }
-
+ if (!vRecv.empty())
+ vRecv >> fRelay;
// Disconnect if we connected to ourself
- if (pfrom->fInbound && !connman.CheckIncomingNonce(nNonce))
+ if (pfrom->fInbound && !connman->CheckIncomingNonce(nNonce))
{
LogPrintf("connected to self at %s, disconnecting\n", pfrom->addr.ToString());
pfrom->fDisconnect = true;
return true;
}
- pfrom->addrLocal = addrMe;
if (pfrom->fInbound && addrMe.IsRoutable())
{
SeenLocal(addrMe);
@@ -1247,9 +1292,27 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (pfrom->fInbound)
PushNodeVersion(pfrom, connman, GetAdjustedTime());
- pfrom->fClient = !(pfrom->nServices & NODE_NETWORK);
+ connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERACK));
- if((pfrom->nServices & NODE_WITNESS))
+ pfrom->nServices = nServices;
+ pfrom->SetAddrLocal(addrMe);
+ {
+ LOCK(pfrom->cs_SubVer);
+ pfrom->strSubVer = strSubVer;
+ pfrom->cleanSubVer = cleanSubVer;
+ }
+ pfrom->nStartingHeight = nStartingHeight;
+ pfrom->fClient = !(nServices & NODE_NETWORK);
+ {
+ LOCK(pfrom->cs_filter);
+ pfrom->fRelayTxes = fRelay; // set to true after we get the first filter* message
+ }
+
+ // Change version
+ pfrom->SetSendVersion(nSendVersion);
+ pfrom->nVersion = nVersion;
+
+ if((nServices & NODE_WITNESS))
{
LOCK(cs_main);
State(pfrom->GetId())->fHaveWitness = true;
@@ -1261,11 +1324,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
UpdatePreferredDownload(pfrom, State(pfrom->GetId()));
}
- // Change version
- connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERACK));
- int nSendVersion = std::min(pfrom->nVersion, PROTOCOL_VERSION);
- pfrom->SetSendVersion(nSendVersion);
-
if (!pfrom->fInbound)
{
// Advertise our address
@@ -1275,39 +1333,43 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
FastRandomContext insecure_rand;
if (addr.IsRoutable())
{
- LogPrint("net", "ProcessMessages: advertising address %s\n", addr.ToString());
+ LogPrint(BCLog::NET, "ProcessMessages: advertising address %s\n", addr.ToString());
pfrom->PushAddress(addr, insecure_rand);
} else if (IsPeerAddrLocalGood(pfrom)) {
- addr.SetIP(pfrom->addrLocal);
- LogPrint("net", "ProcessMessages: advertising address %s\n", addr.ToString());
+ addr.SetIP(addrMe);
+ LogPrint(BCLog::NET, "ProcessMessages: advertising address %s\n", addr.ToString());
pfrom->PushAddress(addr, insecure_rand);
}
}
// Get recent addresses
- if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || connman.GetAddressCount() < 1000)
+ if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || connman->GetAddressCount() < 1000)
{
- connman.PushMessage(pfrom, CNetMsgMaker(nSendVersion).Make(NetMsgType::GETADDR));
+ connman->PushMessage(pfrom, CNetMsgMaker(nSendVersion).Make(NetMsgType::GETADDR));
pfrom->fGetAddr = true;
}
- connman.MarkAddressGood(pfrom->addr);
+ connman->MarkAddressGood(pfrom->addr);
}
- pfrom->fSuccessfullyConnected = true;
-
- string remoteAddr;
+ std::string remoteAddr;
if (fLogIPs)
remoteAddr = ", peeraddr=" + pfrom->addr.ToString();
LogPrintf("receive version message: %s: version %d, blocks=%d, us=%s, peer=%d%s\n",
- pfrom->cleanSubVer, pfrom->nVersion,
- pfrom->nStartingHeight, addrMe.ToString(), pfrom->id,
+ cleanSubVer, pfrom->nVersion,
+ pfrom->nStartingHeight, addrMe.ToString(), pfrom->GetId(),
remoteAddr);
int64_t nTimeOffset = nTime - GetTime();
pfrom->nTimeOffset = nTimeOffset;
AddTimeData(pfrom->addr, nTimeOffset);
+ // If the peer is old enough to have the old alert system, send it the final alert.
+ if (pfrom->nVersion <= 70012) {
+ CDataStream finalAlert(ParseHex("60010000000000000000000000ffffff7f00000000ffffff7ffeffff7f01ffffff7f00000000ffffff7f00ffffff7f002f555247454e543a20416c657274206b657920636f6d70726f6d697365642c2075706772616465207265717569726564004630440220653febd6410f470f6bae11cad19c48413becb1ac2c17f908fd0fd53bdc3abd5202206d0e9c96fe88d4a0f01ed9dedae2b6f9e00da94cad0fecaae66ecf689bf71b50"), SER_NETWORK, PROTOCOL_VERSION);
+ connman->PushMessage(pfrom, CNetMsgMaker(nSendVersion).Make("alert", finalAlert));
+ }
+
// Feeler connections exist only to verify if address is online.
if (pfrom->fFeeler) {
assert(pfrom->fInbound == false);
@@ -1326,11 +1388,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
// At this point, the outgoing message serialization version can't change.
- CNetMsgMaker msgMaker(pfrom->GetSendVersion());
+ const CNetMsgMaker msgMaker(pfrom->GetSendVersion());
if (strCommand == NetMsgType::VERACK)
{
- pfrom->SetRecvVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
+ pfrom->SetRecvVersion(std::min(pfrom->nVersion.load(), PROTOCOL_VERSION));
if (!pfrom->fInbound) {
// Mark this node as currently connected, so we update its timestamp later.
@@ -1343,7 +1405,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// We send this to non-NODE NETWORK peers as well, because even
// non-NODE NETWORK peers can announce blocks (such as pruning
// nodes)
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDHEADERS));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDHEADERS));
}
if (pfrom->nVersion >= SHORT_IDS_BLOCKS_VERSION) {
// Tell our peer we are willing to provide version 1 or 2 cmpctblocks
@@ -1354,20 +1416,28 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
bool fAnnounceUsingCMPCTBLOCK = false;
uint64_t nCMPCTBLOCKVersion = 2;
if (pfrom->GetLocalServices() & NODE_WITNESS)
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
nCMPCTBLOCKVersion = 1;
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
}
+ pfrom->fSuccessfullyConnected = true;
}
+ else if (!pfrom->fSuccessfullyConnected)
+ {
+ // Must have a verack message before anything else
+ LOCK(cs_main);
+ Misbehaving(pfrom->GetId(), 1);
+ return false;
+ }
else if (strCommand == NetMsgType::ADDR)
{
- vector<CAddress> vAddr;
+ std::vector<CAddress> vAddr;
vRecv >> vAddr;
// Don't want addr from older versions unless seeding
- if (pfrom->nVersion < CADDR_TIME_VERSION && connman.GetAddressCount() > 1000)
+ if (pfrom->nVersion < CADDR_TIME_VERSION && connman->GetAddressCount() > 1000)
return true;
if (vAddr.size() > 1000)
{
@@ -1377,10 +1447,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
// Store the new addresses
- vector<CAddress> vAddrOk;
+ std::vector<CAddress> vAddrOk;
int64_t nNow = GetAdjustedTime();
int64_t nSince = nNow - 10 * 60;
- BOOST_FOREACH(CAddress& addr, vAddr)
+ for (CAddress& addr : vAddr)
{
if (interruptMsgProc)
return true;
@@ -1401,7 +1471,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (fReachable)
vAddrOk.push_back(addr);
}
- connman.AddNewAddresses(vAddrOk, pfrom->addr, 2 * 60 * 60);
+ connman->AddNewAddresses(vAddrOk, pfrom->addr, 2 * 60 * 60);
if (vAddr.size() < 1000)
pfrom->fGetAddr = false;
if (pfrom->fOneShot)
@@ -1440,7 +1510,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
else if (strCommand == NetMsgType::INV)
{
- vector<CInv> vInv;
+ std::vector<CInv> vInv;
vRecv >> vInv;
if (vInv.size() > MAX_INV_SZ)
{
@@ -1452,24 +1522,20 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
bool fBlocksOnly = !fRelayTxes;
// Allow whitelisted peers to send data other than blocks in blocks only mode if whitelistrelay is true
- if (pfrom->fWhitelisted && GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY))
+ if (pfrom->fWhitelisted && gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY))
fBlocksOnly = false;
LOCK(cs_main);
- uint32_t nFetchFlags = GetFetchFlags(pfrom, chainActive.Tip(), chainparams.GetConsensus());
+ uint32_t nFetchFlags = GetFetchFlags(pfrom);
- std::vector<CInv> vToFetch;
-
- for (unsigned int nInv = 0; nInv < vInv.size(); nInv++)
+ for (CInv &inv : vInv)
{
- CInv &inv = vInv[nInv];
-
if (interruptMsgProc)
return true;
bool fAlreadyHave = AlreadyHave(inv);
- LogPrint("net", "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom->id);
+ LogPrint(BCLog::NET, "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom->GetId());
if (inv.type == MSG_TX) {
inv.type |= nFetchFlags;
@@ -1483,31 +1549,29 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// fell back to inv we probably have a reorg which we should get the headers for first,
// we now only provide a getheaders response here. When we receive the headers, we will
// then ask for the blocks we need.
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash));
- LogPrint("net", "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->id);
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash));
+ LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->GetId());
}
}
else
{
pfrom->AddInventoryKnown(inv);
- if (fBlocksOnly)
- LogPrint("net", "transaction (%s) inv sent in violation of protocol peer=%d\n", inv.hash.ToString(), pfrom->id);
- else if (!fAlreadyHave && !fImporting && !fReindex && !IsInitialBlockDownload())
+ if (fBlocksOnly) {
+ LogPrint(BCLog::NET, "transaction (%s) inv sent in violation of protocol peer=%d\n", inv.hash.ToString(), pfrom->GetId());
+ } else if (!fAlreadyHave && !fImporting && !fReindex && !IsInitialBlockDownload()) {
pfrom->AskFor(inv);
+ }
}
// Track requests for our stuff
GetMainSignals().Inventory(inv.hash);
}
-
- if (!vToFetch.empty())
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vToFetch));
}
else if (strCommand == NetMsgType::GETDATA)
{
- vector<CInv> vInv;
+ std::vector<CInv> vInv;
vRecv >> vInv;
if (vInv.size() > MAX_INV_SZ)
{
@@ -1516,11 +1580,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
return error("message getdata size() = %u", vInv.size());
}
- if (fDebug || (vInv.size() != 1))
- LogPrint("net", "received getdata (%u invsz) peer=%d\n", vInv.size(), pfrom->id);
+ LogPrint(BCLog::NET, "received getdata (%u invsz) peer=%d\n", vInv.size(), pfrom->GetId());
- if ((fDebug && vInv.size() > 0) || (vInv.size() == 1))
- LogPrint("net", "received getdata for: %s peer=%d\n", vInv[0].ToString(), pfrom->id);
+ if (vInv.size() > 0) {
+ LogPrint(BCLog::NET, "received getdata for: %s peer=%d\n", vInv[0].ToString(), pfrom->GetId());
+ }
pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end());
ProcessGetData(pfrom, chainparams.GetConsensus(), connman, interruptMsgProc);
@@ -1559,12 +1623,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (pindex)
pindex = chainActive.Next(pindex);
int nLimit = 500;
- LogPrint("net", "getblocks %d to %s limit %d from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), nLimit, pfrom->id);
+ LogPrint(BCLog::NET, "getblocks %d to %s limit %d from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), nLimit, pfrom->GetId());
for (; pindex; pindex = chainActive.Next(pindex))
{
if (pindex->GetBlockHash() == hashStop)
{
- LogPrint("net", " getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
+ LogPrint(BCLog::NET, " getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
break;
}
// If pruning, don't inv blocks unless we have on disk and are likely to still have
@@ -1572,7 +1636,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
const int nPrunedBlocksLikelyToHave = MIN_BLOCKS_TO_KEEP - 3600 / chainparams.GetConsensus().nPowTargetSpacing;
if (fPruneMode && (!(pindex->nStatus & BLOCK_HAVE_DATA) || pindex->nHeight <= chainActive.Tip()->nHeight - nPrunedBlocksLikelyToHave))
{
- LogPrint("net", " getblocks stopping, pruned or too old block at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
+ LogPrint(BCLog::NET, " getblocks stopping, pruned or too old block at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
break;
}
pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash()));
@@ -1580,7 +1644,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
{
// When this block is requested, we'll send an inv that'll
// trigger the peer to getblocks the next batch of inventory.
- LogPrint("net", " getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
+ LogPrint(BCLog::NET, " getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
pfrom->hashContinue = pindex->GetBlockHash();
break;
}
@@ -1609,7 +1673,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
BlockMap::iterator it = mapBlockIndex.find(req.blockhash);
if (it == mapBlockIndex.end() || !(it->second->nStatus & BLOCK_HAVE_DATA)) {
- LogPrintf("Peer %d sent us a getblocktxn for a block we don't have", pfrom->id);
+ LogPrintf("Peer %d sent us a getblocktxn for a block we don't have", pfrom->GetId());
return true;
}
@@ -1621,7 +1685,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// might maliciously send lots of getblocktxn requests to trigger
// expensive disk reads, because it will require the peer to
// actually receive all the data read from disk over the network.
- LogPrint("net", "Peer %d sent us a getblocktxn for a block > %i deep", pfrom->id, MAX_BLOCKTXN_DEPTH);
+ LogPrint(BCLog::NET, "Peer %d sent us a getblocktxn for a block > %i deep", pfrom->GetId(), MAX_BLOCKTXN_DEPTH);
CInv inv;
inv.type = State(pfrom->GetId())->fWantsCmpctWitness ? MSG_WITNESS_BLOCK : MSG_BLOCK;
inv.hash = req.blockhash;
@@ -1646,12 +1710,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
LOCK(cs_main);
if (IsInitialBlockDownload() && !pfrom->fWhitelisted) {
- LogPrint("net", "Ignoring getheaders from peer=%d because node is in initial block download\n", pfrom->id);
+ LogPrint(BCLog::NET, "Ignoring getheaders from peer=%d because node is in initial block download\n", pfrom->GetId());
return true;
}
CNodeState *nodestate = State(pfrom->GetId());
- const CBlockIndex* pindex = NULL;
+ const CBlockIndex* pindex = nullptr;
if (locator.IsNull())
{
// If locator is null, return the hashStop block
@@ -1669,16 +1733,16 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
// we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end
- vector<CBlock> vHeaders;
+ std::vector<CBlock> vHeaders;
int nLimit = MAX_HEADERS_RESULTS;
- LogPrint("net", "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), pfrom->id);
+ LogPrint(BCLog::NET, "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), pfrom->GetId());
for (; pindex; pindex = chainActive.Next(pindex))
{
vHeaders.push_back(pindex->GetBlockHeader());
if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop)
break;
}
- // pindex can be NULL either if we sent chainActive.Tip() OR
+ // pindex can be nullptr either if we sent chainActive.Tip() OR
// if our peer has chainActive.Tip() (and thus we are sending an empty
// headers message). In both cases it's safe to update
// pindexBestHeaderSent to be our tip.
@@ -1691,7 +1755,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// will re-announce the new block via headers (or compact blocks again)
// in the SendMessages logic.
nodestate->pindexBestHeaderSent = pindex ? pindex : chainActive.Tip();
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders));
}
@@ -1699,14 +1763,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
{
// Stop processing the transaction early if
// We are in blocks only mode and peer is either not whitelisted or whitelistrelay is off
- if (!fRelayTxes && (!pfrom->fWhitelisted || !GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)))
+ if (!fRelayTxes && (!pfrom->fWhitelisted || !gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)))
{
- LogPrint("net", "transaction sent in violation of protocol peer=%d\n", pfrom->id);
+ LogPrint(BCLog::NET, "transaction sent in violation of protocol peer=%d\n", pfrom->GetId());
return true;
}
- deque<COutPoint> vWorkQueue;
- vector<uint256> vEraseQueue;
+ std::deque<COutPoint> vWorkQueue;
+ std::vector<uint256> vEraseQueue;
CTransactionRef ptx;
vRecv >> ptx;
const CTransaction& tx = *ptx;
@@ -1722,7 +1786,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->setAskFor.erase(inv.hash);
mapAlreadyAskedFor.erase(inv.hash);
- if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, ptx, true, &fMissingInputs)) {
+ std::list<CTransactionRef> lRemovedTxn;
+
+ if (!AlreadyHave(inv) &&
+ AcceptToMemoryPool(mempool, state, ptx, &fMissingInputs, &lRemovedTxn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
mempool.check(pcoinsTip);
RelayTransaction(tx, connman);
for (unsigned int i = 0; i < tx.vout.size(); i++) {
@@ -1731,13 +1798,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->nLastTXTime = GetTime();
- LogPrint("mempool", "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n",
- pfrom->id,
+ LogPrint(BCLog::MEMPOOL, "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n",
+ pfrom->GetId(),
tx.GetHash().ToString(),
mempool.size(), mempool.DynamicMemoryUsage() / 1000);
// Recursively process any orphan transactions that depended on this one
- set<NodeId> setMisbehaving;
+ std::set<NodeId> setMisbehaving;
while (!vWorkQueue.empty()) {
auto itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue.front());
vWorkQueue.pop_front();
@@ -1760,8 +1827,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (setMisbehaving.count(fromPeer))
continue;
- if (AcceptToMemoryPool(mempool, stateDummy, porphanTx, true, &fMissingInputs2)) {
- LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString());
+ if (AcceptToMemoryPool(mempool, stateDummy, porphanTx, &fMissingInputs2, &lRemovedTxn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
+ LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", orphanHash.ToString());
RelayTransaction(orphanTx, connman);
for (unsigned int i = 0; i < orphanTx.vout.size(); i++) {
vWorkQueue.emplace_back(orphanHash, i);
@@ -1776,11 +1843,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Punish peer that gave us an invalid orphan tx
Misbehaving(fromPeer, nDos);
setMisbehaving.insert(fromPeer);
- LogPrint("mempool", " invalid orphan tx %s\n", orphanHash.ToString());
+ LogPrint(BCLog::MEMPOOL, " invalid orphan tx %s\n", orphanHash.ToString());
}
// Has inputs but not accepted to mempool
- // Probably non-standard or insufficient fee/priority
- LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString());
+ // Probably non-standard or insufficient fee
+ LogPrint(BCLog::MEMPOOL, " removed orphan tx %s\n", orphanHash.ToString());
vEraseQueue.push_back(orphanHash);
if (!orphanTx.HasWitness() && !stateDummy.CorruptionPossible()) {
// Do not use rejection cache for witness transactions or
@@ -1794,21 +1861,21 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
}
- BOOST_FOREACH(uint256 hash, vEraseQueue)
+ for (uint256 hash : vEraseQueue)
EraseOrphanTx(hash);
}
else if (fMissingInputs)
{
bool fRejectedParents = false; // It may be the case that the orphans parents have all been rejected
- BOOST_FOREACH(const CTxIn& txin, tx.vin) {
+ for (const CTxIn& txin : tx.vin) {
if (recentRejects->contains(txin.prevout.hash)) {
fRejectedParents = true;
break;
}
}
if (!fRejectedParents) {
- uint32_t nFetchFlags = GetFetchFlags(pfrom, chainActive.Tip(), chainparams.GetConsensus());
- BOOST_FOREACH(const CTxIn& txin, tx.vin) {
+ uint32_t nFetchFlags = GetFetchFlags(pfrom);
+ for (const CTxIn& txin : tx.vin) {
CInv _inv(MSG_TX | nFetchFlags, txin.prevout.hash);
pfrom->AddInventoryKnown(_inv);
if (!AlreadyHave(_inv)) pfrom->AskFor(_inv);
@@ -1816,12 +1883,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
AddOrphanTx(ptx, pfrom->GetId());
// DoS prevention: do not allow mapOrphanTransactions to grow unbounded
- unsigned int nMaxOrphanTx = (unsigned int)std::max((int64_t)0, GetArg("-maxorphantx", DEFAULT_MAX_ORPHAN_TRANSACTIONS));
+ unsigned int nMaxOrphanTx = (unsigned int)std::max((int64_t)0, gArgs.GetArg("-maxorphantx", DEFAULT_MAX_ORPHAN_TRANSACTIONS));
unsigned int nEvicted = LimitOrphanTxSize(nMaxOrphanTx);
- if (nEvicted > 0)
- LogPrint("mempool", "mapOrphan overflow, removed %u tx\n", nEvicted);
+ if (nEvicted > 0) {
+ LogPrint(BCLog::MEMPOOL, "mapOrphan overflow, removed %u tx\n", nEvicted);
+ }
} else {
- LogPrint("mempool", "not keeping orphan with rejected parents %s\n",tx.GetHash().ToString());
+ LogPrint(BCLog::MEMPOOL, "not keeping orphan with rejected parents %s\n",tx.GetHash().ToString());
// We will continue to reject this tx since it has rejected
// parents so avoid re-requesting it from other peers.
recentRejects->insert(tx.GetHash());
@@ -1833,9 +1901,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// See https://github.com/bitcoin/bitcoin/issues/8279 for details.
assert(recentRejects);
recentRejects->insert(tx.GetHash());
+ if (RecursiveDynamicUsage(*ptx) < 100000) {
+ AddToCompactExtraTransactions(ptx);
+ }
+ } else if (tx.HasWitness() && RecursiveDynamicUsage(*ptx) < 100000) {
+ AddToCompactExtraTransactions(ptx);
}
- if (pfrom->fWhitelisted && GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) {
+ if (pfrom->fWhitelisted && gArgs.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) {
// Always relay transactions received from whitelisted peers, even
// if they were already in the mempool or rejected from it due
// to policy, allowing the node to function as a gateway for
@@ -1846,21 +1919,25 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// case.
int nDoS = 0;
if (!state.IsInvalid(nDoS) || nDoS == 0) {
- LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->id);
+ LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->GetId());
RelayTransaction(tx, connman);
} else {
- LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s)\n", tx.GetHash().ToString(), pfrom->id, FormatStateMessage(state));
+ LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s)\n", tx.GetHash().ToString(), pfrom->GetId(), FormatStateMessage(state));
}
}
}
+
+ for (const CTransactionRef& removedTx : lRemovedTxn)
+ AddToCompactExtraTransactions(removedTx);
+
int nDoS = 0;
if (state.IsInvalid(nDoS))
{
- LogPrint("mempoolrej", "%s from peer=%d was not accepted: %s\n", tx.GetHash().ToString(),
- pfrom->id,
+ LogPrint(BCLog::MEMPOOLREJ, "%s from peer=%d was not accepted: %s\n", tx.GetHash().ToString(),
+ pfrom->GetId(),
FormatStateMessage(state));
- if (state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
+ if (state.GetRejectCode() > 0 && state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash));
if (nDoS > 0) {
Misbehaving(pfrom->GetId(), nDoS);
@@ -1880,12 +1957,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (mapBlockIndex.find(cmpctblock.header.hashPrevBlock) == mapBlockIndex.end()) {
// Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers
if (!IsInitialBlockDownload())
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256()));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256()));
return true;
}
}
- const CBlockIndex *pindex = NULL;
+ const CBlockIndex *pindex = nullptr;
CValidationState state;
if (!ProcessNewBlockHeaders({cmpctblock.header}, state, chainparams, &pindex)) {
int nDoS;
@@ -1894,7 +1971,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
LOCK(cs_main);
Misbehaving(pfrom->GetId(), nDoS);
}
- LogPrintf("Peer %d sent us invalid header via cmpctblock\n", pfrom->id);
+ LogPrintf("Peer %d sent us invalid header via cmpctblock\n", pfrom->GetId());
return true;
}
}
@@ -1922,7 +1999,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
assert(pindex);
UpdateBlockAvailability(pfrom->GetId(), pindex->GetBlockHash());
- std::map<uint256, pair<NodeId, list<QueuedBlock>::iterator> >::iterator blockInFlightIt = mapBlocksInFlight.find(pindex->GetBlockHash());
+ std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> >::iterator blockInFlightIt = mapBlocksInFlight.find(pindex->GetBlockHash());
bool fAlreadyInFlight = blockInFlightIt != mapBlocksInFlight.end();
if (pindex->nStatus & BLOCK_HAVE_DATA) // Nothing to do here
@@ -1934,8 +2011,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// We requested this block for some reason, but our mempool will probably be useless
// so we just grab the block via normal getdata
std::vector<CInv> vInv(1);
- vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom, pindex->pprev, chainparams.GetConsensus()), cmpctblock.header.GetHash());
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
+ vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHash());
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
}
return true;
}
@@ -1957,29 +2034,29 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (pindex->nHeight <= chainActive.Height() + 2) {
if ((!fAlreadyInFlight && nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) ||
(fAlreadyInFlight && blockInFlightIt->second.first == pfrom->GetId())) {
- list<QueuedBlock>::iterator *queuedBlockIt = NULL;
- if (!MarkBlockAsInFlight(pfrom->GetId(), pindex->GetBlockHash(), chainparams.GetConsensus(), pindex, &queuedBlockIt)) {
+ std::list<QueuedBlock>::iterator* queuedBlockIt = nullptr;
+ if (!MarkBlockAsInFlight(pfrom->GetId(), pindex->GetBlockHash(), pindex, &queuedBlockIt)) {
if (!(*queuedBlockIt)->partialBlock)
(*queuedBlockIt)->partialBlock.reset(new PartiallyDownloadedBlock(&mempool));
else {
// The block was already in flight using compact blocks from the same peer
- LogPrint("net", "Peer sent us compact block we were already syncing!\n");
+ LogPrint(BCLog::NET, "Peer sent us compact block we were already syncing!\n");
return true;
}
}
PartiallyDownloadedBlock& partialBlock = *(*queuedBlockIt)->partialBlock;
- ReadStatus status = partialBlock.InitData(cmpctblock);
+ ReadStatus status = partialBlock.InitData(cmpctblock, vExtraTxnForCompact);
if (status == READ_STATUS_INVALID) {
MarkBlockAsReceived(pindex->GetBlockHash()); // Reset in-flight state in case of whitelist
Misbehaving(pfrom->GetId(), 100);
- LogPrintf("Peer %d sent us invalid compact block\n", pfrom->id);
+ LogPrintf("Peer %d sent us invalid compact block\n", pfrom->GetId());
return true;
} else if (status == READ_STATUS_FAILED) {
// Duplicate txindexes, the block is now in-flight, so just request it
std::vector<CInv> vInv(1);
- vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom, pindex->pprev, chainparams.GetConsensus()), cmpctblock.header.GetHash());
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
+ vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHash());
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
return true;
}
@@ -1996,7 +2073,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
fProcessBLOCKTXN = true;
} else {
req.blockhash = pindex->GetBlockHash();
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETBLOCKTXN, req));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETBLOCKTXN, req));
}
} else {
// This block is either already in flight from a different
@@ -2005,7 +2082,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Optimistically try to reconstruct anyway since we might be
// able to without any round trips.
PartiallyDownloadedBlock tempBlock(&mempool);
- ReadStatus status = tempBlock.InitData(cmpctblock);
+ ReadStatus status = tempBlock.InitData(cmpctblock, vExtraTxnForCompact);
if (status != READ_STATUS_OK) {
// TODO: don't ignore failures
return true;
@@ -2021,8 +2098,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// We requested this block, but its far into the future, so our
// mempool will probably be useless - request the block normally
std::vector<CInv> vInv(1);
- vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom, pindex->pprev, chainparams.GetConsensus()), cmpctblock.header.GetHash());
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
+ vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHash());
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
return true;
} else {
// If this was an announce-cmpctblock, we want the same treatment as a header message
@@ -2050,9 +2127,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
bool fNewBlock = false;
ProcessNewBlock(chainparams, pblock, true, &fNewBlock);
- if (fNewBlock)
+ if (fNewBlock) {
pfrom->nLastBlockTime = GetTime();
-
+ } else {
+ LOCK(cs_main);
+ mapBlockSource.erase(pblock->GetHash());
+ }
LOCK(cs_main); // hold cs_main for CBlockIndex::IsValid()
if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS)) {
// Clear download state for this block, which is in
@@ -2075,10 +2155,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
{
LOCK(cs_main);
- map<uint256, pair<NodeId, list<QueuedBlock>::iterator> >::iterator it = mapBlocksInFlight.find(resp.blockhash);
+ std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> >::iterator it = mapBlocksInFlight.find(resp.blockhash);
if (it == mapBlocksInFlight.end() || !it->second.second->partialBlock ||
it->second.first != pfrom->GetId()) {
- LogPrint("net", "Peer %d sent us block transactions for block we weren't expecting\n", pfrom->id);
+ LogPrint(BCLog::NET, "Peer %d sent us block transactions for block we weren't expecting\n", pfrom->GetId());
return true;
}
@@ -2087,13 +2167,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (status == READ_STATUS_INVALID) {
MarkBlockAsReceived(resp.blockhash); // Reset in-flight state in case of whitelist
Misbehaving(pfrom->GetId(), 100);
- LogPrintf("Peer %d sent us invalid compact block/non-matching block transactions\n", pfrom->id);
+ LogPrintf("Peer %d sent us invalid compact block/non-matching block transactions\n", pfrom->GetId());
return true;
} else if (status == READ_STATUS_FAILED) {
// Might have collided, fall back to getdata now :(
std::vector<CInv> invs;
- invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(pfrom, chainActive.Tip(), chainparams.GetConsensus()), resp.blockhash));
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, invs));
+ invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(pfrom), resp.blockhash));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, invs));
} else {
// Block is either okay, or possibly we received
// READ_STATUS_CHECKBLOCK_FAILED.
@@ -2127,8 +2207,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Since we requested this block (it was in mapBlocksInFlight), force it to be processed,
// even if it would not be a candidate for new tip (missing previous block, chain not long enough, etc)
ProcessNewBlock(chainparams, pblock, true, &fNewBlock);
- if (fNewBlock)
+ if (fNewBlock) {
pfrom->nLastBlockTime = GetTime();
+ } else {
+ LOCK(cs_main);
+ mapBlockSource.erase(pblock->GetHash());
+ }
}
}
@@ -2155,7 +2239,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
return true;
}
- const CBlockIndex *pindexLast = NULL;
+ const CBlockIndex *pindexLast = nullptr;
{
LOCK(cs_main);
CNodeState *nodestate = State(pfrom->GetId());
@@ -2170,12 +2254,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// nUnconnectingHeaders gets reset back to 0.
if (mapBlockIndex.find(headers[0].hashPrevBlock) == mapBlockIndex.end() && nCount < MAX_BLOCKS_TO_ANNOUNCE) {
nodestate->nUnconnectingHeaders++;
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256()));
- LogPrint("net", "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n",
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256()));
+ LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n",
headers[0].GetHash().ToString(),
headers[0].hashPrevBlock.ToString(),
pindexBestHeader->nHeight,
- pfrom->id, nodestate->nUnconnectingHeaders);
+ pfrom->GetId(), nodestate->nUnconnectingHeaders);
// Set hashLastUnknownBlock for this peer, so that if we
// eventually get the headers - even from a different peer -
// we can use this peer to download.
@@ -2213,7 +2297,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
LOCK(cs_main);
CNodeState *nodestate = State(pfrom->GetId());
if (nodestate->nUnconnectingHeaders > 0) {
- LogPrint("net", "peer=%d: resetting nUnconnectingHeaders (%d -> 0)\n", pfrom->id, nodestate->nUnconnectingHeaders);
+ LogPrint(BCLog::NET, "peer=%d: resetting nUnconnectingHeaders (%d -> 0)\n", pfrom->GetId(), nodestate->nUnconnectingHeaders);
}
nodestate->nUnconnectingHeaders = 0;
@@ -2224,15 +2308,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Headers message had its maximum size; the peer may have more headers.
// TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue
// from there instead.
- LogPrint("net", "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->id, pfrom->nStartingHeight);
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256()));
+ LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->GetId(), pfrom->nStartingHeight);
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256()));
}
bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus());
// If this set of headers is valid and ends in a block with at least as
// much work as our tip, download as much as possible.
if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && chainActive.Tip()->nChainWork <= pindexLast->nChainWork) {
- vector<const CBlockIndex *> vToFetch;
+ std::vector<const CBlockIndex*> vToFetch;
const CBlockIndex *pindexWalk = pindexLast;
// Calculate all the blocks we'd need to switch to pindexLast, up to a limit.
while (pindexWalk && !chainActive.Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
@@ -2249,25 +2333,25 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// the main chain -- this shouldn't really happen. Bail out on the
// direct fetch and rely on parallel download instead.
if (!chainActive.Contains(pindexWalk)) {
- LogPrint("net", "Large reorg, won't direct fetch to %s (%d)\n",
+ LogPrint(BCLog::NET, "Large reorg, won't direct fetch to %s (%d)\n",
pindexLast->GetBlockHash().ToString(),
pindexLast->nHeight);
} else {
- vector<CInv> vGetData;
+ std::vector<CInv> vGetData;
// Download as much as possible, from earliest to latest.
- BOOST_REVERSE_FOREACH(const CBlockIndex *pindex, vToFetch) {
+ for (const CBlockIndex *pindex : reverse_iterate(vToFetch)) {
if (nodestate->nBlocksInFlight >= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
// Can't download any more from this peer
break;
}
- uint32_t nFetchFlags = GetFetchFlags(pfrom, pindex->pprev, chainparams.GetConsensus());
+ uint32_t nFetchFlags = GetFetchFlags(pfrom);
vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
- MarkBlockAsInFlight(pfrom->GetId(), pindex->GetBlockHash(), chainparams.GetConsensus(), pindex);
- LogPrint("net", "Requesting block %s from peer=%d\n",
- pindex->GetBlockHash().ToString(), pfrom->id);
+ MarkBlockAsInFlight(pfrom->GetId(), pindex->GetBlockHash(), pindex);
+ LogPrint(BCLog::NET, "Requesting block %s from peer=%d\n",
+ pindex->GetBlockHash().ToString(), pfrom->GetId());
}
if (vGetData.size() > 1) {
- LogPrint("net", "Downloading blocks toward %s (%d) via headers direct fetch\n",
+ LogPrint(BCLog::NET, "Downloading blocks toward %s (%d) via headers direct fetch\n",
pindexLast->GetBlockHash().ToString(), pindexLast->nHeight);
}
if (vGetData.size() > 0) {
@@ -2275,7 +2359,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// In any case, we want to download using a compact block, not a regular one
vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash);
}
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vGetData));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vGetData));
}
}
}
@@ -2287,7 +2371,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
vRecv >> *pblock;
- LogPrint("net", "received block %s peer=%d\n", pblock->GetHash().ToString(), pfrom->id);
+ LogPrint(BCLog::NET, "received block %s peer=%d\n", pblock->GetHash().ToString(), pfrom->GetId());
// Process all blocks from whitelisted peers, even if not requested,
// unless we're still syncing with the network.
@@ -2306,8 +2390,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
bool fNewBlock = false;
ProcessNewBlock(chainparams, pblock, forceProcessing, &fNewBlock);
- if (fNewBlock)
+ if (fNewBlock) {
pfrom->nLastBlockTime = GetTime();
+ } else {
+ LOCK(cs_main);
+ mapBlockSource.erase(pblock->GetHash());
+ }
}
@@ -2319,22 +2407,22 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Making nodes which are behind NAT and can only make outgoing connections ignore
// the getaddr message mitigates the attack.
if (!pfrom->fInbound) {
- LogPrint("net", "Ignoring \"getaddr\" from outbound connection. peer=%d\n", pfrom->id);
+ LogPrint(BCLog::NET, "Ignoring \"getaddr\" from outbound connection. peer=%d\n", pfrom->GetId());
return true;
}
// Only send one GetAddr response per connection to reduce resource waste
// and discourage addr stamping of INV announcements.
if (pfrom->fSentAddr) {
- LogPrint("net", "Ignoring repeated \"getaddr\". peer=%d\n", pfrom->id);
+ LogPrint(BCLog::NET, "Ignoring repeated \"getaddr\". peer=%d\n", pfrom->GetId());
return true;
}
pfrom->fSentAddr = true;
pfrom->vAddrToSend.clear();
- vector<CAddress> vAddr = connman.GetAddresses();
+ std::vector<CAddress> vAddr = connman->GetAddresses();
FastRandomContext insecure_rand;
- BOOST_FOREACH(const CAddress &addr, vAddr)
+ for (const CAddress &addr : vAddr)
pfrom->PushAddress(addr, insecure_rand);
}
@@ -2343,14 +2431,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
{
if (!(pfrom->GetLocalServices() & NODE_BLOOM) && !pfrom->fWhitelisted)
{
- LogPrint("net", "mempool request with bloom filters disabled, disconnect peer=%d\n", pfrom->GetId());
+ LogPrint(BCLog::NET, "mempool request with bloom filters disabled, disconnect peer=%d\n", pfrom->GetId());
pfrom->fDisconnect = true;
return true;
}
- if (connman.OutboundTargetReached(false) && !pfrom->fWhitelisted)
+ if (connman->OutboundTargetReached(false) && !pfrom->fWhitelisted)
{
- LogPrint("net", "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId());
+ LogPrint(BCLog::NET, "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId());
pfrom->fDisconnect = true;
return true;
}
@@ -2377,7 +2465,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// it, if the remote node sends a ping once per second and this node takes 5
// seconds to respond to each, the 5th ping the remote sends would appear to
// return very quickly.
- connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::PONG, nonce));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::PONG, nonce));
}
}
@@ -2402,7 +2490,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);
+ pfrom->nMinPingUsecTime = std::min(pfrom->nMinPingUsecTime.load(), pingUsecTime);
} else {
// This should never happen
sProblem = "Timing mishap";
@@ -2426,8 +2514,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
if (!(sProblem.empty())) {
- LogPrint("net", "pong peer=%d: %s, %x expected, %x received, %u bytes\n",
- pfrom->id,
+ LogPrint(BCLog::NET, "pong peer=%d: %s, %x expected, %x received, %u bytes\n",
+ pfrom->GetId(),
sProblem,
pfrom->nPingNonceSent,
nonce,
@@ -2463,7 +2551,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
else if (strCommand == NetMsgType::FILTERADD)
{
- vector<unsigned char> vData;
+ std::vector<unsigned char> vData;
vRecv >> vData;
// Nodes must NEVER send a data item > 520 bytes (the max size for a script data object,
@@ -2496,31 +2584,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->fRelayTxes = true;
}
-
- else if (strCommand == NetMsgType::REJECT)
- {
- if (fDebug) {
- try {
- string strMsg; unsigned char ccode; string strReason;
- vRecv >> LIMITED_STRING(strMsg, CMessageHeader::COMMAND_SIZE) >> ccode >> LIMITED_STRING(strReason, MAX_REJECT_MESSAGE_LENGTH);
-
- ostringstream ss;
- ss << strMsg << " code " << itostr(ccode) << ": " << strReason;
-
- if (strMsg == NetMsgType::BLOCK || strMsg == NetMsgType::TX)
- {
- uint256 hash;
- vRecv >> hash;
- ss << ": hash " << hash.ToString();
- }
- LogPrint("net", "Reject %s\n", SanitizeString(ss.str()));
- } catch (const std::ios_base::failure&) {
- // Avoid feedback loops by preventing reject messages from triggering a new reject message.
- LogPrint("net", "Unparseable reject message received\n");
- }
- }
- }
-
else if (strCommand == NetMsgType::FEEFILTER) {
CAmount newFeeFilter = 0;
vRecv >> newFeeFilter;
@@ -2529,7 +2592,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
LOCK(pfrom->cs_feeFilter);
pfrom->minFeeFilter = newFeeFilter;
}
- LogPrint("net", "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom->id);
+ LogPrint(BCLog::NET, "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom->GetId());
}
}
@@ -2540,7 +2603,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
else {
// Ignore unknown commands for extensibility
- LogPrint("net", "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->id);
+ LogPrint(BCLog::NET, "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->GetId());
}
@@ -2548,7 +2611,37 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
return true;
}
-bool ProcessMessages(CNode* pfrom, CConnman& connman, std::atomic<bool>& interruptMsgProc)
+static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman* connman)
+{
+ AssertLockHeld(cs_main);
+ CNodeState &state = *State(pnode->GetId());
+
+ for (const CBlockReject& reject : state.rejects) {
+ connman->PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, (std::string)NetMsgType::BLOCK, reject.chRejectCode, reject.strRejectReason, reject.hashBlock));
+ }
+ state.rejects.clear();
+
+ if (state.fShouldBan) {
+ state.fShouldBan = false;
+ if (pnode->fWhitelisted)
+ LogPrintf("Warning: not punishing whitelisted peer %s!\n", pnode->addr.ToString());
+ else if (pnode->fAddnode)
+ LogPrintf("Warning: not punishing addnoded peer %s!\n", pnode->addr.ToString());
+ else {
+ pnode->fDisconnect = true;
+ if (pnode->addr.IsLocal())
+ LogPrintf("Warning: not banning local peer %s!\n", pnode->addr.ToString());
+ else
+ {
+ connman->Ban(pnode->addr, BanReasonNodeMisbehaving);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& interruptMsgProc)
{
const CChainParams& chainparams = Params();
//
@@ -2570,96 +2663,100 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman, std::atomic<bool>& interru
// this maintains the order of responses
if (!pfrom->vRecvGetData.empty()) return true;
- // Don't bother if send buffer is too full to respond anyway
- if (pfrom->fPauseSend)
- return false;
+ // Don't bother if send buffer is too full to respond anyway
+ if (pfrom->fPauseSend)
+ return false;
- std::list<CNetMessage> msgs;
- {
- LOCK(pfrom->cs_vProcessMsg);
- if (pfrom->vProcessMsg.empty())
- return false;
- // Just take one message
- msgs.splice(msgs.begin(), pfrom->vProcessMsg, pfrom->vProcessMsg.begin());
- pfrom->nProcessQueueSize -= msgs.front().vRecv.size() + CMessageHeader::HEADER_SIZE;
- pfrom->fPauseRecv = pfrom->nProcessQueueSize > connman.GetReceiveFloodSize();
- fMoreWork = !pfrom->vProcessMsg.empty();
- }
- CNetMessage& msg(msgs.front());
-
- msg.SetVersion(pfrom->GetRecvVersion());
- // Scan for message start
- if (memcmp(msg.hdr.pchMessageStart, chainparams.MessageStart(), CMessageHeader::MESSAGE_START_SIZE) != 0) {
- LogPrintf("PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n", SanitizeString(msg.hdr.GetCommand()), pfrom->id);
- pfrom->fDisconnect = true;
+ std::list<CNetMessage> msgs;
+ {
+ LOCK(pfrom->cs_vProcessMsg);
+ if (pfrom->vProcessMsg.empty())
return false;
- }
+ // Just take one message
+ msgs.splice(msgs.begin(), pfrom->vProcessMsg, pfrom->vProcessMsg.begin());
+ pfrom->nProcessQueueSize -= msgs.front().vRecv.size() + CMessageHeader::HEADER_SIZE;
+ pfrom->fPauseRecv = pfrom->nProcessQueueSize > connman->GetReceiveFloodSize();
+ fMoreWork = !pfrom->vProcessMsg.empty();
+ }
+ CNetMessage& msg(msgs.front());
+
+ msg.SetVersion(pfrom->GetRecvVersion());
+ // Scan for message start
+ if (memcmp(msg.hdr.pchMessageStart, chainparams.MessageStart(), CMessageHeader::MESSAGE_START_SIZE) != 0) {
+ LogPrintf("PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n", SanitizeString(msg.hdr.GetCommand()), pfrom->GetId());
+ pfrom->fDisconnect = true;
+ return false;
+ }
- // Read header
- CMessageHeader& hdr = msg.hdr;
- if (!hdr.IsValid(chainparams.MessageStart()))
- {
- LogPrintf("PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\n", SanitizeString(hdr.GetCommand()), pfrom->id);
- return fMoreWork;
- }
- string strCommand = hdr.GetCommand();
+ // Read header
+ CMessageHeader& hdr = msg.hdr;
+ if (!hdr.IsValid(chainparams.MessageStart()))
+ {
+ LogPrintf("PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\n", SanitizeString(hdr.GetCommand()), pfrom->GetId());
+ return fMoreWork;
+ }
+ std::string strCommand = hdr.GetCommand();
- // Message size
- unsigned int nMessageSize = hdr.nMessageSize;
+ // Message size
+ unsigned int nMessageSize = hdr.nMessageSize;
- // Checksum
- CDataStream& vRecv = msg.vRecv;
- const uint256& hash = msg.GetMessageHash();
- if (memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) != 0)
+ // Checksum
+ CDataStream& vRecv = msg.vRecv;
+ const uint256& hash = msg.GetMessageHash();
+ if (memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) != 0)
+ {
+ LogPrintf("%s(%s, %u bytes): CHECKSUM ERROR expected %s was %s\n", __func__,
+ SanitizeString(strCommand), nMessageSize,
+ HexStr(hash.begin(), hash.begin()+CMessageHeader::CHECKSUM_SIZE),
+ HexStr(hdr.pchChecksum, hdr.pchChecksum+CMessageHeader::CHECKSUM_SIZE));
+ return fMoreWork;
+ }
+
+ // Process message
+ bool fRet = false;
+ try
+ {
+ fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime, chainparams, connman, interruptMsgProc);
+ if (interruptMsgProc)
+ return false;
+ if (!pfrom->vRecvGetData.empty())
+ fMoreWork = true;
+ }
+ catch (const std::ios_base::failure& e)
+ {
+ connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, std::string("error parsing message")));
+ if (strstr(e.what(), "end of data"))
{
- LogPrintf("%s(%s, %u bytes): CHECKSUM ERROR expected %s was %s\n", __func__,
- SanitizeString(strCommand), nMessageSize,
- HexStr(hash.begin(), hash.begin()+CMessageHeader::CHECKSUM_SIZE),
- HexStr(hdr.pchChecksum, hdr.pchChecksum+CMessageHeader::CHECKSUM_SIZE));
- return fMoreWork;
+ // Allow exceptions from under-length message on vRecv
+ LogPrintf("%s(%s, %u bytes): Exception '%s' caught, normally caused by a message being shorter than its stated length\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
}
-
- // Process message
- bool fRet = false;
- try
+ else if (strstr(e.what(), "size too large"))
{
- fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime, chainparams, connman, interruptMsgProc);
- if (interruptMsgProc)
- return false;
- if (!pfrom->vRecvGetData.empty())
- fMoreWork = true;
+ // Allow exceptions from over-long size
+ LogPrintf("%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
}
- catch (const std::ios_base::failure& e)
+ else if (strstr(e.what(), "non-canonical ReadCompactSize()"))
{
- connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, string("error parsing message")));
- if (strstr(e.what(), "end of data"))
- {
- // Allow exceptions from under-length message on vRecv
- LogPrintf("%s(%s, %u bytes): Exception '%s' caught, normally caused by a message being shorter than its stated length\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
- }
- else if (strstr(e.what(), "size too large"))
- {
- // Allow exceptions from over-long size
- LogPrintf("%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
- }
- else if (strstr(e.what(), "non-canonical ReadCompactSize()"))
- {
- // Allow exceptions from non-canonical encoding
- LogPrintf("%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
- }
- else
- {
- PrintExceptionContinue(&e, "ProcessMessages()");
- }
+ // Allow exceptions from non-canonical encoding
+ LogPrintf("%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
}
- catch (const std::exception& e) {
+ else
+ {
PrintExceptionContinue(&e, "ProcessMessages()");
- } catch (...) {
- PrintExceptionContinue(NULL, "ProcessMessages()");
}
+ }
+ catch (const std::exception& e) {
+ PrintExceptionContinue(&e, "ProcessMessages()");
+ } catch (...) {
+ PrintExceptionContinue(nullptr, "ProcessMessages()");
+ }
+
+ if (!fRet) {
+ LogPrintf("%s(%s, %u bytes) FAILED peer=%d\n", __func__, SanitizeString(strCommand), nMessageSize, pfrom->GetId());
+ }
- if (!fRet)
- LogPrintf("%s(%s, %u bytes) FAILED peer=%d\n", __func__, SanitizeString(strCommand), nMessageSize, pfrom->id);
+ LOCK(cs_main);
+ SendRejectsAndCheckIfBanned(pfrom, connman);
return fMoreWork;
}
@@ -2668,7 +2765,7 @@ class CompareInvMempoolOrder
{
CTxMemPool *mp;
public:
- CompareInvMempoolOrder(CTxMemPool *_mempool)
+ explicit CompareInvMempoolOrder(CTxMemPool *_mempool)
{
mp = _mempool;
}
@@ -2681,16 +2778,16 @@ public:
}
};
-bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsgProc)
+bool PeerLogicValidation::SendMessages(CNode* pto, std::atomic<bool>& interruptMsgProc)
{
const Consensus::Params& consensusParams = Params().GetConsensus();
{
- // Don't send anything until we get its version message
- if (pto->nVersion == 0 || pto->fDisconnect)
+ // Don't send anything until the version handshake is complete
+ if (!pto->fSuccessfullyConnected || pto->fDisconnect)
return true;
// If we get here, the outgoing message serialization version is set and can't change.
- CNetMsgMaker msgMaker(pto->GetSendVersion());
+ const CNetMsgMaker msgMaker(pto->GetSendVersion());
//
// Message: ping
@@ -2713,11 +2810,11 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
pto->nPingUsecStart = GetTimeMicros();
if (pto->nVersion > BIP0031_VERSION) {
pto->nPingNonceSent = nonce;
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::PING, nonce));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::PING, nonce));
} else {
// Peer is too old to support ping command with nonce, pong will never arrive.
pto->nPingNonceSent = 0;
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::PING));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::PING));
}
}
@@ -2725,30 +2822,10 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
if (!lockMain)
return true;
+ if (SendRejectsAndCheckIfBanned(pto, connman))
+ return true;
CNodeState &state = *State(pto->GetId());
- BOOST_FOREACH(const CBlockReject& reject, state.rejects)
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::REJECT, (string)NetMsgType::BLOCK, reject.chRejectCode, reject.strRejectReason, reject.hashBlock));
- state.rejects.clear();
-
- if (state.fShouldBan) {
- state.fShouldBan = false;
- if (pto->fWhitelisted)
- LogPrintf("Warning: not punishing whitelisted peer %s!\n", pto->addr.ToString());
- else if (pto->fAddnode)
- LogPrintf("Warning: not punishing addnoded peer %s!\n", pto->addr.ToString());
- else {
- pto->fDisconnect = true;
- if (pto->addr.IsLocal())
- LogPrintf("Warning: not banning local peer %s!\n", pto->addr.ToString());
- else
- {
- connman.Ban(pto->addr, BanReasonNodeMisbehaving);
- }
- return true;
- }
- }
-
// Address refresh broadcast
int64_t nNow = GetTimeMicros();
if (!IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow) {
@@ -2761,9 +2838,9 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
//
if (pto->nNextAddrSend < nNow) {
pto->nNextAddrSend = PoissonNextSend(nNow, AVG_ADDRESS_BROADCAST_INTERVAL);
- vector<CAddress> vAddr;
+ std::vector<CAddress> vAddr;
vAddr.reserve(pto->vAddrToSend.size());
- BOOST_FOREACH(const CAddress& addr, pto->vAddrToSend)
+ for (const CAddress& addr : pto->vAddrToSend)
{
if (!pto->addrKnown.contains(addr.GetKey()))
{
@@ -2772,27 +2849,28 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
// receiver rejects addr messages larger than 1000
if (vAddr.size() >= 1000)
{
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr));
vAddr.clear();
}
}
}
pto->vAddrToSend.clear();
if (!vAddr.empty())
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr));
// we only send the big addr message once
if (pto->vAddrToSend.capacity() > 40)
pto->vAddrToSend.shrink_to_fit();
}
// Start block sync
- if (pindexBestHeader == NULL)
+ if (pindexBestHeader == nullptr)
pindexBestHeader = chainActive.Tip();
bool fFetch = state.fPreferredDownload || (nPreferredDownload == 0 && !pto->fClient && !pto->fOneShot); // Download if this is a nice peer, or we have no nice peers and this one might do.
if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) {
// Only actively request headers from a single peer, unless we're close to today.
if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) {
state.fSyncStarted = true;
+ state.nHeadersSyncTimeout = GetTimeMicros() + HEADERS_DOWNLOAD_TIMEOUT_BASE + HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER * (GetAdjustedTime() - pindexBestHeader->GetBlockTime())/(consensusParams.nPowTargetSpacing);
nSyncStarted++;
const CBlockIndex *pindexStart = pindexBestHeader;
/* If possible, start at the block preceding the currently
@@ -2804,8 +2882,8 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
got back an empty response. */
if (pindexStart->pprev)
pindexStart = pindexStart->pprev;
- LogPrint("net", "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->id, pto->nStartingHeight);
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256()));
+ LogPrint(BCLog::NET, "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->GetId(), pto->nStartingHeight);
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256()));
}
}
@@ -2814,7 +2892,7 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
// transactions become unconfirmed and spams other nodes.
if (!fReindex && !fImporting && !IsInitialBlockDownload())
{
- GetMainSignals().Broadcast(nTimeBestReceived, &connman);
+ GetMainSignals().Broadcast(nTimeBestReceived, connman);
}
//
@@ -2829,19 +2907,19 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
// blocks, or if the peer doesn't want headers, just
// add all to the inv queue.
LOCK(pto->cs_inventory);
- vector<CBlock> vHeaders;
+ std::vector<CBlock> vHeaders;
bool fRevertToInv = ((!state.fPreferHeaders &&
(!state.fPreferHeaderAndIDs || pto->vBlockHashesToAnnounce.size() > 1)) ||
pto->vBlockHashesToAnnounce.size() > MAX_BLOCKS_TO_ANNOUNCE);
- const CBlockIndex *pBestIndex = NULL; // last header queued for delivery
- ProcessBlockAvailability(pto->id); // ensure pindexBestKnownBlock is up-to-date
+ const CBlockIndex *pBestIndex = nullptr; // last header queued for delivery
+ ProcessBlockAvailability(pto->GetId()); // ensure pindexBestKnownBlock is up-to-date
if (!fRevertToInv) {
bool fFoundStartingHeader = false;
// Try to find first header that our peer doesn't have, and
// then send all headers past that one. If we come across any
// headers that aren't on chainActive, give up.
- BOOST_FOREACH(const uint256 &hash, pto->vBlockHashesToAnnounce) {
+ for (const uint256 &hash : pto->vBlockHashesToAnnounce) {
BlockMap::iterator mi = mapBlockIndex.find(hash);
assert(mi != mapBlockIndex.end());
const CBlockIndex *pindex = mi->second;
@@ -2850,7 +2928,7 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
fRevertToInv = true;
break;
}
- if (pBestIndex != NULL && pindex->pprev != pBestIndex) {
+ if (pBestIndex != nullptr && pindex->pprev != pBestIndex) {
// This means that the list of blocks to announce don't
// connect to each other.
// This shouldn't really be possible to hit during
@@ -2871,7 +2949,7 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
vHeaders.push_back(pindex->GetBlockHeader());
} else if (PeerHasHeader(&state, pindex)) {
continue; // keep looking for the first new block
- } else if (pindex->pprev == NULL || PeerHasHeader(&state, pindex->pprev)) {
+ } else if (pindex->pprev == nullptr || PeerHasHeader(&state, pindex->pprev)) {
// Peer doesn't have this header but they do have the prior one.
// Start sending headers.
fFoundStartingHeader = true;
@@ -2888,8 +2966,8 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
if (vHeaders.size() == 1 && state.fPreferHeaderAndIDs) {
// We only send up to 1 block as header-and-ids, as otherwise
// probably means we're doing an initial-ish-sync or they're slow
- LogPrint("net", "%s sending header-and-ids %s to peer=%d\n", __func__,
- vHeaders.front().GetHash().ToString(), pto->id);
+ LogPrint(BCLog::NET, "%s sending header-and-ids %s to peer=%d\n", __func__,
+ vHeaders.front().GetHash().ToString(), pto->GetId());
int nSendFlags = state.fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS;
@@ -2897,11 +2975,11 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
{
LOCK(cs_most_recent_block);
if (most_recent_block_hash == pBestIndex->GetBlockHash()) {
- if (state.fWantsCmpctWitness)
- connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *most_recent_compact_block));
+ if (state.fWantsCmpctWitness || !fWitnessesPresentInMostRecentCompactBlock)
+ connman->PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *most_recent_compact_block));
else {
CBlockHeaderAndShortTxIDs cmpctblock(*most_recent_block, state.fWantsCmpctWitness);
- connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));
+ connman->PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));
}
fGotBlockFromCache = true;
}
@@ -2911,20 +2989,20 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
bool ret = ReadBlockFromDisk(block, pBestIndex, consensusParams);
assert(ret);
CBlockHeaderAndShortTxIDs cmpctblock(block, state.fWantsCmpctWitness);
- connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));
+ connman->PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));
}
state.pindexBestHeaderSent = pBestIndex;
} else if (state.fPreferHeaders) {
if (vHeaders.size() > 1) {
- LogPrint("net", "%s: %u headers, range (%s, %s), to peer=%d\n", __func__,
+ LogPrint(BCLog::NET, "%s: %u headers, range (%s, %s), to peer=%d\n", __func__,
vHeaders.size(),
vHeaders.front().GetHash().ToString(),
- vHeaders.back().GetHash().ToString(), pto->id);
+ vHeaders.back().GetHash().ToString(), pto->GetId());
} else {
- LogPrint("net", "%s: sending header %s to peer=%d\n", __func__,
- vHeaders.front().GetHash().ToString(), pto->id);
+ LogPrint(BCLog::NET, "%s: sending header %s to peer=%d\n", __func__,
+ vHeaders.front().GetHash().ToString(), pto->GetId());
}
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::HEADERS, vHeaders));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::HEADERS, vHeaders));
state.pindexBestHeaderSent = pBestIndex;
} else
fRevertToInv = true;
@@ -2943,15 +3021,15 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
// This should be very rare and could be optimized out.
// Just log for now.
if (chainActive[pindex->nHeight] != pindex) {
- LogPrint("net", "Announcing block %s not on main chain (tip=%s)\n",
+ LogPrint(BCLog::NET, "Announcing block %s not on main chain (tip=%s)\n",
hashToAnnounce.ToString(), chainActive.Tip()->GetBlockHash().ToString());
}
// If the peer's chain has this block, don't inv it back.
if (!PeerHasHeader(&state, pindex)) {
pto->PushInventory(CInv(MSG_BLOCK, hashToAnnounce));
- LogPrint("net", "%s: sending inv peer=%d hash=%s\n", __func__,
- pto->id, hashToAnnounce.ToString());
+ LogPrint(BCLog::NET, "%s: sending inv peer=%d hash=%s\n", __func__,
+ pto->GetId(), hashToAnnounce.ToString());
}
}
}
@@ -2961,16 +3039,16 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
//
// Message: inventory
//
- vector<CInv> vInv;
+ std::vector<CInv> vInv;
{
LOCK(pto->cs_inventory);
vInv.reserve(std::max<size_t>(pto->vInventoryBlockToSend.size(), INVENTORY_BROADCAST_MAX));
// Add blocks
- BOOST_FOREACH(const uint256& hash, pto->vInventoryBlockToSend) {
+ for (const uint256& hash : pto->vInventoryBlockToSend) {
vInv.push_back(CInv(MSG_BLOCK, hash));
if (vInv.size() == MAX_INV_SZ) {
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
vInv.clear();
}
}
@@ -3016,7 +3094,7 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
pto->filterInventoryKnown.insert(hash);
vInv.push_back(inv);
if (vInv.size() == MAX_INV_SZ) {
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
vInv.clear();
}
}
@@ -3026,7 +3104,7 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
// Determine transactions to relay
if (fSendTrickle) {
// Produce a vector with all candidates for sending
- vector<std::set<uint256>::iterator> vInvTx;
+ std::vector<std::set<uint256>::iterator> vInvTx;
vInvTx.reserve(pto->setInventoryTxToSend.size());
for (std::set<uint256>::iterator it = pto->setInventoryTxToSend.begin(); it != pto->setInventoryTxToSend.end(); it++) {
vInvTx.push_back(it);
@@ -3082,7 +3160,7 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
}
}
if (vInv.size() == MAX_INV_SZ) {
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
vInv.clear();
}
pto->filterInventoryKnown.insert(hash);
@@ -3090,7 +3168,7 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
}
}
if (!vInv.empty())
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
// Detect whether we're stalling
nNow = GetTimeMicros();
@@ -3098,7 +3176,7 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
// Stalling only triggers when the block download window cannot move. During normal steady state,
// the download window should be much larger than the to-be-downloaded set of blocks, so disconnection
// should only happen during initial block download.
- LogPrintf("Peer=%d is stalling block download, disconnecting\n", pto->id);
+ LogPrintf("Peer=%d is stalling block download, disconnecting\n", pto->GetId());
pto->fDisconnect = true;
return true;
}
@@ -3111,31 +3189,64 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
QueuedBlock &queuedBlock = state.vBlocksInFlight.front();
int nOtherPeersWithValidatedDownloads = nPeersWithValidatedDownloads - (state.nBlocksInFlightValidHeaders > 0);
if (nNow > state.nDownloadingSince + consensusParams.nPowTargetSpacing * (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads)) {
- LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", queuedBlock.hash.ToString(), pto->id);
+ LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", queuedBlock.hash.ToString(), pto->GetId());
pto->fDisconnect = true;
return true;
}
}
+ // Check for headers sync timeouts
+ if (state.fSyncStarted && state.nHeadersSyncTimeout < std::numeric_limits<int64_t>::max()) {
+ // Detect whether this is a stalling initial-headers-sync peer
+ if (pindexBestHeader->GetBlockTime() <= GetAdjustedTime() - 24*60*60) {
+ if (nNow > state.nHeadersSyncTimeout && nSyncStarted == 1 && (nPreferredDownload - state.fPreferredDownload >= 1)) {
+ // Disconnect a (non-whitelisted) peer if it is our only sync peer,
+ // and we have others we could be using instead.
+ // Note: If all our peers are inbound, then we won't
+ // disconnect our sync peer for stalling; we have bigger
+ // problems if we can't get any outbound peers.
+ if (!pto->fWhitelisted) {
+ LogPrintf("Timeout downloading headers from peer=%d, disconnecting\n", pto->GetId());
+ pto->fDisconnect = true;
+ return true;
+ } else {
+ LogPrintf("Timeout downloading headers from whitelisted peer=%d, not disconnecting\n", pto->GetId());
+ // Reset the headers sync state so that we have a
+ // chance to try downloading from a different peer.
+ // Note: this will also result in at least one more
+ // getheaders message to be sent to
+ // this peer (eventually).
+ state.fSyncStarted = false;
+ nSyncStarted--;
+ state.nHeadersSyncTimeout = 0;
+ }
+ }
+ } else {
+ // After we've caught up once, reset the timeout so we can't trigger
+ // disconnect later.
+ state.nHeadersSyncTimeout = std::numeric_limits<int64_t>::max();
+ }
+ }
+
//
// Message: getdata (blocks)
//
- vector<CInv> vGetData;
+ std::vector<CInv> vGetData;
if (!pto->fClient && (fFetch || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
- vector<const CBlockIndex*> vToDownload;
+ std::vector<const CBlockIndex*> vToDownload;
NodeId staller = -1;
FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller, consensusParams);
- BOOST_FOREACH(const CBlockIndex *pindex, vToDownload) {
- uint32_t nFetchFlags = GetFetchFlags(pto, pindex->pprev, consensusParams);
+ for (const CBlockIndex *pindex : vToDownload) {
+ uint32_t nFetchFlags = GetFetchFlags(pto);
vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
- MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), consensusParams, pindex);
- LogPrint("net", "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(),
- pindex->nHeight, pto->id);
+ MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), pindex);
+ LogPrint(BCLog::NET, "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(),
+ pindex->nHeight, pto->GetId());
}
if (state.nBlocksInFlight == 0 && staller != -1) {
if (State(staller)->nStallingSince == 0) {
State(staller)->nStallingSince = nNow;
- LogPrint("net", "Stall started peer=%d\n", staller);
+ LogPrint(BCLog::NET, "Stall started peer=%d\n", staller);
}
}
}
@@ -3148,12 +3259,11 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
const CInv& inv = (*pto->mapAskFor.begin()).second;
if (!AlreadyHave(inv))
{
- if (fDebug)
- LogPrint("net", "Requesting %s peer=%d\n", inv.ToString(), pto->id);
+ LogPrint(BCLog::NET, "Requesting %s peer=%d\n", inv.ToString(), pto->GetId());
vGetData.push_back(inv);
if (vGetData.size() >= 1000)
{
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData));
vGetData.clear();
}
} else {
@@ -3163,25 +3273,24 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
pto->mapAskFor.erase(pto->mapAskFor.begin());
}
if (!vGetData.empty())
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData));
//
// Message: feefilter
//
// We don't want white listed peers to filter txs to us if we have -whitelistforcerelay
- if (pto->nVersion >= FEEFILTER_VERSION && GetBoolArg("-feefilter", DEFAULT_FEEFILTER) &&
- !(pto->fWhitelisted && GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY))) {
- CAmount currentFilter = mempool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK();
+ if (pto->nVersion >= FEEFILTER_VERSION && gArgs.GetBoolArg("-feefilter", DEFAULT_FEEFILTER) &&
+ !(pto->fWhitelisted && gArgs.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY))) {
+ CAmount currentFilter = mempool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK();
int64_t timeNow = GetTimeMicros();
if (timeNow > pto->nextSendTimeFeeFilter) {
static CFeeRate default_feerate(DEFAULT_MIN_RELAY_TX_FEE);
static FeeFilterRounder filterRounder(default_feerate);
CAmount filterToSend = filterRounder.round(currentFilter);
- // If we don't allow free transactions, then we always have a fee filter of at least minRelayTxFee
- if (GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) <= 0)
- filterToSend = std::max(filterToSend, ::minRelayTxFee.GetFeePerK());
+ // We always have a fee filter of at least minRelayTxFee
+ filterToSend = std::max(filterToSend, ::minRelayTxFee.GetFeePerK());
if (filterToSend != pto->lastSentFeeFilter) {
- connman.PushMessage(pto, msgMaker.Make(NetMsgType::FEEFILTER, filterToSend));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::FEEFILTER, filterToSend));
pto->lastSentFeeFilter = filterToSend;
}
pto->nextSendTimeFeeFilter = PoissonNextSend(timeNow, AVG_FEEFILTER_BROADCAST_INTERVAL);
diff --git a/src/net_processing.h b/src/net_processing.h
index eaa0305136..79745cdd42 100644
--- a/src/net_processing.h
+++ b/src/net_processing.h
@@ -9,22 +9,44 @@
#include "net.h"
#include "validationinterface.h"
-/** Register with a network node to receive its signals */
-void RegisterNodeSignals(CNodeSignals& nodeSignals);
-/** Unregister a network node */
-void UnregisterNodeSignals(CNodeSignals& nodeSignals);
+/** Default for -maxorphantx, maximum number of orphan transactions kept in memory */
+static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100;
+/** Expiration time for orphan transactions in seconds */
+static const int64_t ORPHAN_TX_EXPIRE_TIME = 20 * 60;
+/** Minimum time between orphan transactions expire time checks in seconds */
+static const int64_t ORPHAN_TX_EXPIRE_INTERVAL = 5 * 60;
+/** Default number of orphan+recently-replaced txn to keep around for block reconstruction */
+static const unsigned int DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN = 100;
+/** Headers download timeout expressed in microseconds
+ * Timeout = base + per_header * (expected number of headers) */
+static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_BASE = 15 * 60 * 1000000; // 15 minutes
+static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER = 1000; // 1ms/header
-class PeerLogicValidation : public CValidationInterface {
+class PeerLogicValidation : public CValidationInterface, public NetEventsInterface {
private:
CConnman* connman;
public:
- PeerLogicValidation(CConnman* connmanIn);
+ explicit PeerLogicValidation(CConnman* connman);
- virtual void SyncTransaction(const CTransaction& tx, const CBlockIndex* pindex, int nPosInBlock);
- virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload);
- virtual void BlockChecked(const CBlock& block, const CValidationState& state);
- virtual void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock);
+ void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected, const std::vector<CTransactionRef>& vtxConflicted) override;
+ void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override;
+ void BlockChecked(const CBlock& block, const CValidationState& state) override;
+ void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock) override;
+
+
+ void InitializeNode(CNode* pnode) override;
+ void FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) override;
+ /** Process protocol messages received from a given node */
+ bool ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt) override;
+ /**
+ * Send queued protocol messages to be sent to a give node.
+ *
+ * @param[in] pto The node which we are sending messages to.
+ * @param[in] interrupt Interrupt condition for processing threads
+ * @return True if there is more work to be done
+ */
+ bool SendMessages(CNode* pto, std::atomic<bool>& interrupt) override;
};
struct CNodeStateStats {
@@ -39,16 +61,4 @@ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats);
/** Increase a node's misbehavior score. */
void Misbehaving(NodeId nodeid, int howmuch);
-/** Process protocol messages received from a given node */
-bool ProcessMessages(CNode* pfrom, CConnman& connman, std::atomic<bool>& interrupt);
-/**
- * Send queued protocol messages to be sent to a give node.
- *
- * @param[in] pto The node which we are sending messages to.
- * @param[in] connman The connection manager for that node.
- * @param[in] interrupt Interrupt condition for processing threads
- * @return True if there is more work to be done
- */
-bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interrupt);
-
#endif // BITCOIN_NET_PROCESSING_H
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index ab07270f3f..b8a261c921 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -15,6 +15,9 @@
static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43};
+// 0xFD + sha256("bitcoin")[0:5]
+static const unsigned char g_internal_prefix[] = { 0xFD, 0x6B, 0x88, 0xC0, 0x87, 0x24 };
+
void CNetAddr::Init()
{
memset(ip, 0, sizeof(ip));
@@ -42,6 +45,18 @@ void CNetAddr::SetRaw(Network network, const uint8_t *ip_in)
}
}
+bool CNetAddr::SetInternal(const std::string &name)
+{
+ if (name.empty()) {
+ return false;
+ }
+ unsigned char hash[32] = {};
+ CSHA256().Write((const unsigned char*)name.data(), name.size()).Finalize(hash);
+ memcpy(ip, g_internal_prefix, sizeof(g_internal_prefix));
+ memcpy(ip + sizeof(g_internal_prefix), hash, sizeof(ip) - sizeof(g_internal_prefix));
+ return true;
+}
+
bool CNetAddr::SetSpecial(const std::string &strName)
{
if (strName.size()>6 && strName.substr(strName.size() - 6, 6) == ".onion") {
@@ -84,7 +99,7 @@ bool CNetAddr::IsIPv4() const
bool CNetAddr::IsIPv6() const
{
- return (!IsIPv4() && !IsTor());
+ return (!IsIPv4() && !IsTor() && !IsInternal());
}
bool CNetAddr::IsRFC1918() const
@@ -179,12 +194,6 @@ bool CNetAddr::IsLocal() const
return false;
}
-bool CNetAddr::IsMulticast() const
-{
- return (IsIPv4() && (GetByte(3) & 0xF0) == 0xE0)
- || (GetByte(15) == 0xFF);
-}
-
bool CNetAddr::IsValid() const
{
// Cleanup 3-byte shifted addresses caused by garbage in size field
@@ -205,6 +214,9 @@ bool CNetAddr::IsValid() const
if (IsRFC3849())
return false;
+ if (IsInternal())
+ return false;
+
if (IsIPv4())
{
// INADDR_NONE
@@ -223,11 +235,19 @@ bool CNetAddr::IsValid() const
bool CNetAddr::IsRoutable() const
{
- return IsValid() && !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) || IsRFC4843() || IsLocal());
+ return IsValid() && !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) || IsRFC4843() || IsLocal() || IsInternal());
+}
+
+bool CNetAddr::IsInternal() const
+{
+ return memcmp(ip, g_internal_prefix, sizeof(g_internal_prefix)) == 0;
}
enum Network CNetAddr::GetNetwork() const
{
+ if (IsInternal())
+ return NET_INTERNAL;
+
if (!IsRoutable())
return NET_UNROUTABLE;
@@ -244,12 +264,14 @@ std::string CNetAddr::ToStringIP() const
{
if (IsTor())
return EncodeBase32(&ip[6], 10) + ".onion";
+ if (IsInternal())
+ return EncodeBase32(ip + sizeof(g_internal_prefix), sizeof(ip) - sizeof(g_internal_prefix)) + ".internal";
CService serv(*this, 0);
struct sockaddr_storage sockaddr;
socklen_t socklen = sizeof(sockaddr);
if (serv.GetSockAddr((struct sockaddr*)&sockaddr, &socklen)) {
char name[1025] = "";
- if (!getnameinfo((const struct sockaddr*)&sockaddr, socklen, name, sizeof(name), NULL, 0, NI_NUMERICHOST))
+ if (!getnameinfo((const struct sockaddr*)&sockaddr, socklen, name, sizeof(name), nullptr, 0, NI_NUMERICHOST))
return std::string(name);
}
if (IsIPv4())
@@ -311,9 +333,15 @@ std::vector<unsigned char> CNetAddr::GetGroup() const
nClass = 255;
nBits = 0;
}
-
- // all unroutable addresses belong to the same group
- if (!IsRoutable())
+ // all internal-usage addresses get their own group
+ if (IsInternal())
+ {
+ nClass = NET_INTERNAL;
+ nStartByte = sizeof(g_internal_prefix);
+ nBits = (sizeof(ip) - sizeof(g_internal_prefix)) * 8;
+ }
+ // all other unroutable addresses belong to the same group
+ else if (!IsRoutable())
{
nClass = NET_UNROUTABLE;
nBits = 0;
@@ -379,7 +407,7 @@ static const int NET_UNKNOWN = NET_MAX + 0;
static const int NET_TEREDO = NET_MAX + 1;
int static GetExtNetwork(const CNetAddr *addr)
{
- if (addr == NULL)
+ if (addr == nullptr)
return NET_UNKNOWN;
if (addr->IsRFC4380())
return NET_TEREDO;
@@ -399,7 +427,7 @@ int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const
REACH_PRIVATE
};
- if (!IsRoutable())
+ if (!IsRoutable() || IsInternal())
return REACH_UNREACHABLE;
int ourNet = GetExtNetwork(this);
@@ -545,7 +573,7 @@ std::vector<unsigned char> CService::GetKey() const
{
std::vector<unsigned char> vKey;
vKey.resize(18);
- memcpy(&vKey[0], ip, 16);
+ memcpy(vKey.data(), ip, 16);
vKey[16] = port / 0x100;
vKey[17] = port & 0x0FF;
return vKey;
@@ -558,7 +586,7 @@ std::string CService::ToStringPort() const
std::string CService::ToStringIPPort() const
{
- if (IsIPv4() || IsTor()) {
+ if (IsIPv4() || IsTor() || IsInternal()) {
return ToStringIP() + ":" + ToStringPort();
} else {
return "[" + ToStringIP() + "]:" + ToStringPort();
@@ -570,11 +598,6 @@ std::string CService::ToString() const
return ToStringIPPort();
}
-void CService::SetPort(unsigned short portIn)
-{
- port = portIn;
-}
-
CSubNet::CSubNet():
valid(false)
{
diff --git a/src/netaddress.h b/src/netaddress.h
index bc430dd823..6ca99b36b5 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -22,6 +22,7 @@ enum Network
NET_IPV4,
NET_IPV6,
NET_TOR,
+ NET_INTERNAL,
NET_MAX,
};
@@ -35,7 +36,7 @@ class CNetAddr
public:
CNetAddr();
- CNetAddr(const struct in_addr& ipv4Addr);
+ explicit CNetAddr(const struct in_addr& ipv4Addr);
void Init();
void SetIP(const CNetAddr& ip);
@@ -45,11 +46,17 @@ class CNetAddr
*/
void SetRaw(Network network, const uint8_t *data);
+ /**
+ * Transform an arbitrary string into a non-routable ipv6 address.
+ * Useful for mapping resolved addresses back to their source.
+ */
+ bool SetInternal(const std::string& name);
+
bool SetSpecial(const std::string &strName); // for Tor addresses
bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0)
bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor)
bool IsRFC1918() const; // IPv4 private networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12)
- bool IsRFC2544() const; // IPv4 inter-network communcations (192.18.0.0/15)
+ bool IsRFC2544() const; // IPv4 inter-network communications (192.18.0.0/15)
bool IsRFC6598() const; // IPv4 ISP-level NAT (100.64.0.0/10)
bool IsRFC5737() const; // IPv4 documentation addresses (192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24)
bool IsRFC3849() const; // IPv6 documentation address (2001:0DB8::/32)
@@ -64,8 +71,8 @@ class CNetAddr
bool IsTor() const;
bool IsLocal() const;
bool IsRoutable() const;
+ bool IsInternal() const;
bool IsValid() const;
- bool IsMulticast() const;
enum Network GetNetwork() const;
std::string ToString() const;
std::string ToStringIP() const;
@@ -73,9 +80,9 @@ class CNetAddr
uint64_t GetHash() const;
bool GetInAddr(struct in_addr* pipv4Addr) const;
std::vector<unsigned char> GetGroup() const;
- int GetReachabilityFrom(const CNetAddr *paddrPartner = NULL) const;
+ int GetReachabilityFrom(const CNetAddr *paddrPartner = nullptr) const;
- CNetAddr(const struct in6_addr& pipv6Addr, const uint32_t scope = 0);
+ explicit CNetAddr(const struct in6_addr& pipv6Addr, const uint32_t scope = 0);
bool GetIn6Addr(struct in6_addr* pipv6Addr) const;
friend bool operator==(const CNetAddr& a, const CNetAddr& b);
@@ -139,9 +146,8 @@ class CService : public CNetAddr
CService();
CService(const CNetAddr& ip, unsigned short port);
CService(const struct in_addr& ipv4Addr, unsigned short port);
- CService(const struct sockaddr_in& addr);
+ explicit CService(const struct sockaddr_in& addr);
void Init();
- void SetPort(unsigned short portIn);
unsigned short GetPort() const;
bool GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const;
bool SetSockAddr(const struct sockaddr* paddr);
@@ -154,7 +160,7 @@ class CService : public CNetAddr
std::string ToStringIPPort() const;
CService(const struct in6_addr& ipv6Addr, unsigned short port);
- CService(const struct sockaddr_in6& addr);
+ explicit CService(const struct sockaddr_in6& addr);
ADD_SERIALIZE_METHODS;
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 8fd2a8efd2..5a560bc95a 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -25,7 +25,7 @@
#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
#include <boost/algorithm/string/predicate.hpp> // for startswith() and endswith()
-#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
+#if !defined(HAVE_MSG_NOSIGNAL)
#define MSG_NOSIGNAL 0
#endif
@@ -58,25 +58,6 @@ std::string GetNetworkName(enum Network net) {
}
}
-void SplitHostPort(std::string in, int &portOut, std::string &hostOut) {
- size_t colon = in.find_last_of(':');
- // if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator
- bool fHaveColon = colon != in.npos;
- bool fBracketed = fHaveColon && (in[0]=='[' && in[colon-1]==']'); // if there is a colon, and in[0]=='[', colon is not 0, so in[colon-1] is safe
- bool fMultiColon = fHaveColon && (in.find_last_of(':',colon-1) != in.npos);
- if (fHaveColon && (colon==0 || fBracketed || !fMultiColon)) {
- int32_t n;
- if (ParseInt32(in.substr(colon + 1), &n) && n > 0 && n < 0x10000) {
- in = in.substr(0, colon);
- portOut = n;
- }
- }
- if (in.size()>0 && in[0] == '[' && in[in.size()-1] == ']')
- hostOut = in.substr(1, in.size()-2);
- else
- hostOut = in;
-}
-
bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
{
vIP.clear();
@@ -100,25 +81,30 @@ bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsign
#else
aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST;
#endif
- struct addrinfo *aiRes = NULL;
- int nErr = getaddrinfo(pszName, NULL, &aiHint, &aiRes);
+ struct addrinfo *aiRes = nullptr;
+ int nErr = getaddrinfo(pszName, nullptr, &aiHint, &aiRes);
if (nErr)
return false;
struct addrinfo *aiTrav = aiRes;
- while (aiTrav != NULL && (nMaxSolutions == 0 || vIP.size() < nMaxSolutions))
+ while (aiTrav != nullptr && (nMaxSolutions == 0 || vIP.size() < nMaxSolutions))
{
+ CNetAddr resolved;
if (aiTrav->ai_family == AF_INET)
{
assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in));
- vIP.push_back(CNetAddr(((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr));
+ resolved = CNetAddr(((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr);
}
if (aiTrav->ai_family == AF_INET6)
{
assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6));
struct sockaddr_in6* s6 = (struct sockaddr_in6*) aiTrav->ai_addr;
- vIP.push_back(CNetAddr(s6->sin6_addr, s6->sin6_scope_id));
+ resolved = CNetAddr(s6->sin6_addr, s6->sin6_scope_id);
+ }
+ /* Never allow resolving to an internal address. Consider any such result invalid */
+ if (!resolved.IsInternal()) {
+ vIP.push_back(resolved);
}
aiTrav = aiTrav->ai_next;
@@ -198,6 +184,56 @@ struct timeval MillisToTimeval(int64_t nTimeout)
return timeout;
}
+/** SOCKS version */
+enum SOCKSVersion: uint8_t {
+ SOCKS4 = 0x04,
+ SOCKS5 = 0x05
+};
+
+/** Values defined for METHOD in RFC1928 */
+enum SOCKS5Method: uint8_t {
+ NOAUTH = 0x00, //! No authentication required
+ GSSAPI = 0x01, //! GSSAPI
+ USER_PASS = 0x02, //! Username/password
+ NO_ACCEPTABLE = 0xff, //! No acceptable methods
+};
+
+/** Values defined for CMD in RFC1928 */
+enum SOCKS5Command: uint8_t {
+ CONNECT = 0x01,
+ BIND = 0x02,
+ UDP_ASSOCIATE = 0x03
+};
+
+/** Values defined for REP in RFC1928 */
+enum SOCKS5Reply: uint8_t {
+ SUCCEEDED = 0x00, //! Succeeded
+ GENFAILURE = 0x01, //! General failure
+ NOTALLOWED = 0x02, //! Connection not allowed by ruleset
+ NETUNREACHABLE = 0x03, //! Network unreachable
+ HOSTUNREACHABLE = 0x04, //! Network unreachable
+ CONNREFUSED = 0x05, //! Connection refused
+ TTLEXPIRED = 0x06, //! TTL expired
+ CMDUNSUPPORTED = 0x07, //! Command not supported
+ ATYPEUNSUPPORTED = 0x08, //! Address type not supported
+};
+
+/** Values defined for ATYPE in RFC1928 */
+enum SOCKS5Atyp: uint8_t {
+ IPV4 = 0x01,
+ DOMAINNAME = 0x03,
+ IPV6 = 0x04,
+};
+
+/** Status codes that can be returned by InterruptibleRecv */
+enum class IntrRecvError {
+ OK,
+ Timeout,
+ Disconnected,
+ NetworkError,
+ Interrupted
+};
+
/**
* Read bytes from socket. This will either read the full number of bytes requested
* or return False on error or timeout.
@@ -209,7 +245,7 @@ struct timeval MillisToTimeval(int64_t nTimeout)
*
* @note This function requires that hSocket is in non-blocking mode.
*/
-bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSocket)
+static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, const SOCKET& hSocket)
{
int64_t curTime = GetTimeMillis();
int64_t endTime = curTime + timeout;
@@ -217,96 +253,108 @@ bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSock
// to break off in case of an interruption.
const int64_t maxWait = 1000;
while (len > 0 && curTime < endTime) {
- ssize_t ret = recv(hSocket, data, len, 0); // Optimistically try the recv first
+ ssize_t ret = recv(hSocket, (char*)data, len, 0); // Optimistically try the recv first
if (ret > 0) {
len -= ret;
data += ret;
} else if (ret == 0) { // Unexpected disconnection
- return false;
+ return IntrRecvError::Disconnected;
} else { // Other error or blocking
int nErr = WSAGetLastError();
if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) {
if (!IsSelectableSocket(hSocket)) {
- return false;
+ return IntrRecvError::NetworkError;
}
struct timeval tval = MillisToTimeval(std::min(endTime - curTime, maxWait));
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(hSocket, &fdset);
- int nRet = select(hSocket + 1, &fdset, NULL, NULL, &tval);
+ int nRet = select(hSocket + 1, &fdset, nullptr, nullptr, &tval);
if (nRet == SOCKET_ERROR) {
- return false;
+ return IntrRecvError::NetworkError;
}
} else {
- return false;
+ return IntrRecvError::NetworkError;
}
}
if (interruptSocks5Recv)
- return false;
+ return IntrRecvError::Interrupted;
curTime = GetTimeMillis();
}
- return len == 0;
+ return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout;
}
+/** Credentials for proxy authentication */
struct ProxyCredentials
{
std::string username;
std::string password;
};
-std::string Socks5ErrorString(int err)
+/** Convert SOCKS5 reply to a an error message */
+std::string Socks5ErrorString(uint8_t err)
{
switch(err) {
- case 0x01: return "general failure";
- case 0x02: return "connection not allowed";
- case 0x03: return "network unreachable";
- case 0x04: return "host unreachable";
- case 0x05: return "connection refused";
- case 0x06: return "TTL expired";
- case 0x07: return "protocol error";
- case 0x08: return "address type not supported";
- default: return "unknown";
+ case SOCKS5Reply::GENFAILURE:
+ return "general failure";
+ case SOCKS5Reply::NOTALLOWED:
+ return "connection not allowed";
+ case SOCKS5Reply::NETUNREACHABLE:
+ return "network unreachable";
+ case SOCKS5Reply::HOSTUNREACHABLE:
+ return "host unreachable";
+ case SOCKS5Reply::CONNREFUSED:
+ return "connection refused";
+ case SOCKS5Reply::TTLEXPIRED:
+ return "TTL expired";
+ case SOCKS5Reply::CMDUNSUPPORTED:
+ return "protocol error";
+ case SOCKS5Reply::ATYPEUNSUPPORTED:
+ return "address type not supported";
+ default:
+ return "unknown";
}
}
/** Connect using SOCKS5 (as described in RFC1928) */
static bool Socks5(const std::string& strDest, int port, const ProxyCredentials *auth, SOCKET& hSocket)
{
- LogPrint("net", "SOCKS5 connecting %s\n", strDest);
+ IntrRecvError recvr;
+ LogPrint(BCLog::NET, "SOCKS5 connecting %s\n", strDest);
if (strDest.size() > 255) {
CloseSocket(hSocket);
return error("Hostname too long");
}
// Accepted authentication methods
std::vector<uint8_t> vSocks5Init;
- vSocks5Init.push_back(0x05);
+ vSocks5Init.push_back(SOCKSVersion::SOCKS5);
if (auth) {
- vSocks5Init.push_back(0x02); // # METHODS
- vSocks5Init.push_back(0x00); // X'00' NO AUTHENTICATION REQUIRED
- vSocks5Init.push_back(0x02); // X'02' USERNAME/PASSWORD (RFC1929)
+ vSocks5Init.push_back(0x02); // Number of methods
+ vSocks5Init.push_back(SOCKS5Method::NOAUTH);
+ vSocks5Init.push_back(SOCKS5Method::USER_PASS);
} else {
- vSocks5Init.push_back(0x01); // # METHODS
- vSocks5Init.push_back(0x00); // X'00' NO AUTHENTICATION REQUIRED
+ vSocks5Init.push_back(0x01); // Number of methods
+ vSocks5Init.push_back(SOCKS5Method::NOAUTH);
}
ssize_t ret = send(hSocket, (const char*)vSocks5Init.data(), vSocks5Init.size(), MSG_NOSIGNAL);
if (ret != (ssize_t)vSocks5Init.size()) {
CloseSocket(hSocket);
return error("Error sending to proxy");
}
- char pchRet1[2];
- if (!InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) {
+ uint8_t pchRet1[2];
+ if ((recvr = InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
CloseSocket(hSocket);
LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port);
return false;
}
- if (pchRet1[0] != 0x05) {
+ if (pchRet1[0] != SOCKSVersion::SOCKS5) {
CloseSocket(hSocket);
return error("Proxy failed to initialize");
}
- if (pchRet1[1] == 0x02 && auth) {
+ if (pchRet1[1] == SOCKS5Method::USER_PASS && auth) {
// Perform username/password authentication (as described in RFC1929)
std::vector<uint8_t> vAuth;
- vAuth.push_back(0x01);
+ vAuth.push_back(0x01); // Current (and only) version of user/pass subnegotiation
if (auth->username.size() > 255 || auth->password.size() > 255)
return error("Proxy username or password too long");
vAuth.push_back(auth->username.size());
@@ -318,9 +366,9 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
CloseSocket(hSocket);
return error("Error sending authentication to proxy");
}
- LogPrint("proxy", "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password);
- char pchRetA[2];
- if (!InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) {
+ LogPrint(BCLog::PROXY, "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password);
+ uint8_t pchRetA[2];
+ if ((recvr = InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
CloseSocket(hSocket);
return error("Error reading proxy authentication response");
}
@@ -328,17 +376,17 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
CloseSocket(hSocket);
return error("Proxy authentication unsuccessful");
}
- } else if (pchRet1[1] == 0x00) {
+ } else if (pchRet1[1] == SOCKS5Method::NOAUTH) {
// Perform no authentication
} else {
CloseSocket(hSocket);
return error("Proxy requested wrong authentication method %02x", pchRet1[1]);
}
std::vector<uint8_t> vSocks5;
- vSocks5.push_back(0x05); // VER protocol version
- vSocks5.push_back(0x01); // CMD CONNECT
- vSocks5.push_back(0x00); // RSV Reserved
- vSocks5.push_back(0x03); // ATYP DOMAINNAME
+ vSocks5.push_back(SOCKSVersion::SOCKS5); // VER protocol version
+ vSocks5.push_back(SOCKS5Command::CONNECT); // CMD CONNECT
+ vSocks5.push_back(0x00); // RSV Reserved must be 0
+ vSocks5.push_back(SOCKS5Atyp::DOMAINNAME); // ATYP DOMAINNAME
vSocks5.push_back(strDest.size()); // Length<=255 is checked at beginning of function
vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end());
vSocks5.push_back((port >> 8) & 0xFF);
@@ -348,56 +396,63 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
CloseSocket(hSocket);
return error("Error sending to proxy");
}
- char pchRet2[4];
- if (!InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) {
+ uint8_t pchRet2[4];
+ if ((recvr = InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
CloseSocket(hSocket);
- return error("Error reading proxy response");
+ if (recvr == IntrRecvError::Timeout) {
+ /* If a timeout happens here, this effectively means we timed out while connecting
+ * to the remote node. This is very common for Tor, so do not print an
+ * error message. */
+ return false;
+ } else {
+ return error("Error while reading proxy response");
+ }
}
- if (pchRet2[0] != 0x05) {
+ if (pchRet2[0] != SOCKSVersion::SOCKS5) {
CloseSocket(hSocket);
return error("Proxy failed to accept request");
}
- if (pchRet2[1] != 0x00) {
+ if (pchRet2[1] != SOCKS5Reply::SUCCEEDED) {
// Failures to connect to a peer that are not proxy errors
CloseSocket(hSocket);
LogPrintf("Socks5() connect to %s:%d failed: %s\n", strDest, port, Socks5ErrorString(pchRet2[1]));
return false;
}
- if (pchRet2[2] != 0x00) {
+ if (pchRet2[2] != 0x00) { // Reserved field must be 0
CloseSocket(hSocket);
return error("Error: malformed proxy response");
}
- char pchRet3[256];
+ uint8_t pchRet3[256];
switch (pchRet2[3])
{
- case 0x01: ret = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break;
- case 0x04: ret = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break;
- case 0x03:
+ case SOCKS5Atyp::IPV4: recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break;
+ case SOCKS5Atyp::IPV6: recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break;
+ case SOCKS5Atyp::DOMAINNAME:
{
- ret = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket);
- if (!ret) {
+ recvr = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket);
+ if (recvr != IntrRecvError::OK) {
CloseSocket(hSocket);
return error("Error reading from proxy");
}
int nRecv = pchRet3[0];
- ret = InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, hSocket);
+ recvr = InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, hSocket);
break;
}
default: CloseSocket(hSocket); return error("Error: malformed proxy response");
}
- if (!ret) {
+ if (recvr != IntrRecvError::OK) {
CloseSocket(hSocket);
return error("Error reading from proxy");
}
- if (!InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, hSocket)) {
+ if ((recvr = InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
CloseSocket(hSocket);
return error("Error reading from proxy");
}
- LogPrint("net", "SOCKS5 connected %s\n", strDest);
+ LogPrint(BCLog::NET, "SOCKS5 connected %s\n", strDest);
return true;
}
-bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRet, int nTimeout)
+bool ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRet, int nTimeout)
{
hSocketRet = INVALID_SOCKET;
@@ -412,22 +467,20 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
if (hSocket == INVALID_SOCKET)
return false;
- int set = 1;
#ifdef SO_NOSIGPIPE
+ int set = 1;
// Different way of disabling SIGPIPE on BSD
setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));
#endif
//Disable Nagle's algorithm
-#ifdef WIN32
- setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&set, sizeof(int));
-#else
- setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&set, sizeof(int));
-#endif
+ SetSocketNoDelay(hSocket);
// Set to non-blocking
- if (!SetSocketNonBlocking(hSocket, true))
+ if (!SetSocketNonBlocking(hSocket, true)) {
+ CloseSocket(hSocket);
return error("ConnectSocketDirectly: Setting socket to non-blocking failed, error %s\n", NetworkErrorString(WSAGetLastError()));
+ }
if (connect(hSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
{
@@ -439,10 +492,10 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(hSocket, &fdset);
- int nRet = select(hSocket + 1, NULL, &fdset, NULL, &timeout);
+ int nRet = select(hSocket + 1, nullptr, &fdset, nullptr, &timeout);
if (nRet == 0)
{
- LogPrint("net", "connection to %s timeout\n", addrConnect.ToString());
+ LogPrint(BCLog::NET, "connection to %s timeout\n", addrConnect.ToString());
CloseSocket(hSocket);
return false;
}
@@ -534,7 +587,7 @@ bool IsProxy(const CNetAddr &addr) {
return false;
}
-static bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed)
+bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed)
{
SOCKET hSocket = INVALID_SOCKET;
// first connect to proxy server
@@ -546,7 +599,7 @@ static bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDe
// do socks negotiation
if (proxy.randomize_credentials) {
ProxyCredentials random_auth;
- static std::atomic_int counter;
+ static std::atomic_int counter(0);
random_auth.username = random_auth.password = strprintf("%i", counter++);
if (!Socks5(strDest, (unsigned short)port, &random_auth, hSocket))
return false;
@@ -558,47 +611,6 @@ static bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDe
hSocketRet = hSocket;
return true;
}
-
-bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed)
-{
- proxyType proxy;
- if (outProxyConnectionFailed)
- *outProxyConnectionFailed = false;
-
- if (GetProxy(addrDest.GetNetwork(), proxy))
- return ConnectThroughProxy(proxy, addrDest.ToStringIP(), addrDest.GetPort(), hSocketRet, nTimeout, outProxyConnectionFailed);
- else // no proxy needed (none set for target network)
- return ConnectSocketDirectly(addrDest, hSocketRet, nTimeout);
-}
-
-bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault, int nTimeout, bool *outProxyConnectionFailed)
-{
- std::string strDest;
- int port = portDefault;
-
- if (outProxyConnectionFailed)
- *outProxyConnectionFailed = false;
-
- SplitHostPort(std::string(pszDest), port, strDest);
-
- proxyType proxy;
- GetNameProxy(proxy);
-
- std::vector<CService> addrResolved;
- if (Lookup(strDest.c_str(), addrResolved, port, fNameLookup && !HaveNameProxy(), 256)) {
- if (addrResolved.size() > 0) {
- addr = addrResolved[GetRand(addrResolved.size())];
- return ConnectSocket(addr, hSocketRet, nTimeout);
- }
- }
-
- addr = CService();
-
- if (!HaveNameProxy())
- return false;
- return ConnectThroughProxy(proxy, strDest, port, hSocketRet, nTimeout, outProxyConnectionFailed);
-}
-
bool LookupSubNet(const char* pszName, CSubNet& ret)
{
std::string strSubnet(pszName);
@@ -642,8 +654,8 @@ std::string NetworkErrorString(int err)
char buf[256];
buf[0] = 0;
if(FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,
- NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- buf, sizeof(buf), NULL))
+ nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ buf, sizeof(buf), nullptr))
{
return strprintf("%s (%d)", buf, err);
}
@@ -656,13 +668,14 @@ std::string NetworkErrorString(int err)
std::string NetworkErrorString(int err)
{
char buf[256];
- const char *s = buf;
buf[0] = 0;
/* Too bad there are two incompatible implementations of the
* thread-safe strerror. */
+ const char *s;
#ifdef STRERROR_R_CHAR_P /* GNU variant can return a pointer outside the passed buffer */
s = strerror_r(err, buf, sizeof(buf));
#else /* POSIX variant always returns message in buffer */
+ s = buf;
if (strerror_r(err, buf, sizeof(buf)))
buf[0] = 0;
#endif
@@ -683,7 +696,7 @@ bool CloseSocket(SOCKET& hSocket)
return ret != SOCKET_ERROR;
}
-bool SetSocketNonBlocking(SOCKET& hSocket, bool fNonBlocking)
+bool SetSocketNonBlocking(const SOCKET& hSocket, bool fNonBlocking)
{
if (fNonBlocking) {
#ifdef WIN32
@@ -693,7 +706,6 @@ bool SetSocketNonBlocking(SOCKET& hSocket, bool fNonBlocking)
int fFlags = fcntl(hSocket, F_GETFL, 0);
if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == SOCKET_ERROR) {
#endif
- CloseSocket(hSocket);
return false;
}
} else {
@@ -704,7 +716,6 @@ bool SetSocketNonBlocking(SOCKET& hSocket, bool fNonBlocking)
int fFlags = fcntl(hSocket, F_GETFL, 0);
if (fcntl(hSocket, F_SETFL, fFlags & ~O_NONBLOCK) == SOCKET_ERROR) {
#endif
- CloseSocket(hSocket);
return false;
}
}
@@ -712,6 +723,13 @@ bool SetSocketNonBlocking(SOCKET& hSocket, bool fNonBlocking)
return true;
}
+bool SetSocketNoDelay(const SOCKET& hSocket)
+{
+ int set = 1;
+ int rc = setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&set, sizeof(int));
+ return rc == 0;
+}
+
void InterruptSocks5(bool interrupt)
{
interruptSocks5Recv = interrupt;
diff --git a/src/netbase.h b/src/netbase.h
index dd33b6e47e..e7d7bcb375 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -29,7 +29,7 @@ class proxyType
{
public:
proxyType(): randomize_credentials(false) {}
- proxyType(const CService &_proxy, bool _randomize_credentials=false): proxy(_proxy), randomize_credentials(_randomize_credentials) {}
+ explicit proxyType(const CService &_proxy, bool _randomize_credentials=false): proxy(_proxy), randomize_credentials(_randomize_credentials) {}
bool IsValid() const { return proxy.IsValid(); }
@@ -39,26 +39,28 @@ public:
enum Network ParseNetwork(std::string net);
std::string GetNetworkName(enum Network net);
-void SplitHostPort(std::string in, int &portOut, std::string &hostOut);
bool SetProxy(enum Network net, const proxyType &addrProxy);
bool GetProxy(enum Network net, proxyType &proxyInfoOut);
bool IsProxy(const CNetAddr &addr);
bool SetNameProxy(const proxyType &addrProxy);
bool HaveNameProxy();
+bool GetNameProxy(proxyType &nameProxyOut);
bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup);
bool LookupHost(const char *pszName, CNetAddr& addr, bool fAllowLookup);
bool Lookup(const char *pszName, CService& addr, int portDefault, bool fAllowLookup);
bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions);
CService LookupNumeric(const char *pszName, int portDefault = 0);
bool LookupSubNet(const char *pszName, CSubNet& subnet);
-bool ConnectSocket(const CService &addr, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed = 0);
-bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault, int nTimeout, bool *outProxyConnectionFailed = 0);
+bool ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRet, int nTimeout);
+bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed);
/** Return readable error string for a network error code */
std::string NetworkErrorString(int err);
/** Close socket and set hSocket to INVALID_SOCKET */
bool CloseSocket(SOCKET& hSocket);
/** Disable or enable blocking-mode for a socket */
-bool SetSocketNonBlocking(SOCKET& hSocket, bool fNonBlocking);
+bool SetSocketNonBlocking(const SOCKET& hSocket, bool fNonBlocking);
+/** Set the TCP_NODELAY flag on a socket */
+bool SetSocketNoDelay(const SOCKET& hSocket);
/**
* Convert milliseconds to a struct timeval for e.g. select.
*/
diff --git a/src/netmessagemaker.h b/src/netmessagemaker.h
index 7167434a19..79b2501c5d 100644
--- a/src/netmessagemaker.h
+++ b/src/netmessagemaker.h
@@ -12,10 +12,10 @@
class CNetMsgMaker
{
public:
- CNetMsgMaker(int nVersionIn) : nVersion(nVersionIn){}
+ explicit CNetMsgMaker(int nVersionIn) : nVersion(nVersionIn){}
template <typename... Args>
- CSerializedNetMsg Make(int nFlags, std::string sCommand, Args&&... args)
+ CSerializedNetMsg Make(int nFlags, std::string sCommand, Args&&... args) const
{
CSerializedNetMsg msg;
msg.command = std::move(sCommand);
@@ -24,7 +24,7 @@ public:
}
template <typename... Args>
- CSerializedNetMsg Make(std::string sCommand, Args&&... args)
+ CSerializedNetMsg Make(std::string sCommand, Args&&... args) const
{
return Make(0, std::move(sCommand), std::forward<Args>(args)...);
}
diff --git a/src/amount.cpp b/src/policy/feerate.cpp
index a5f6bc3cd9..a089c02284 100644
--- a/src/amount.cpp
+++ b/src/policy/feerate.cpp
@@ -3,7 +3,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "amount.h"
+#include "feerate.h"
#include "tinyformat.h"
diff --git a/src/policy/feerate.h b/src/policy/feerate.h
new file mode 100644
index 0000000000..3449cdd699
--- /dev/null
+++ b/src/policy/feerate.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-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_POLICY_FEERATE_H
+#define BITCOIN_POLICY_FEERATE_H
+
+#include "amount.h"
+#include "serialize.h"
+
+#include <string>
+
+extern const std::string CURRENCY_UNIT;
+
+/**
+ * Fee rate in satoshis per kilobyte: CAmount / kB
+ */
+class CFeeRate
+{
+private:
+ CAmount nSatoshisPerK; // unit is satoshis-per-1,000-bytes
+
+public:
+ /** Fee rate of 0 satoshis per kB */
+ CFeeRate() : nSatoshisPerK(0) { }
+ template<typename I>
+ CFeeRate(const I _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) {
+ // We've previously had bugs creep in from silent double->int conversion...
+ static_assert(std::is_integral<I>::value, "CFeeRate should be used without floats");
+ }
+ /** Constructor for a fee rate in satoshis per kB. The size in bytes must not exceed (2^63 - 1)*/
+ CFeeRate(const CAmount& nFeePaid, size_t nBytes);
+ /**
+ * Return the fee in satoshis for the given size in bytes.
+ */
+ CAmount GetFee(size_t nBytes) const;
+ /**
+ * Return the fee in satoshis for a size of 1000 bytes
+ */
+ CAmount GetFeePerK() const { return GetFee(1000); }
+ friend bool operator<(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK < b.nSatoshisPerK; }
+ friend bool operator>(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK > b.nSatoshisPerK; }
+ friend bool operator==(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK == b.nSatoshisPerK; }
+ friend bool operator<=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK <= b.nSatoshisPerK; }
+ friend bool operator>=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK >= b.nSatoshisPerK; }
+ friend bool operator!=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK != b.nSatoshisPerK; }
+ CFeeRate& operator+=(const CFeeRate& a) { nSatoshisPerK += a.nSatoshisPerK; return *this; }
+ std::string ToString() const;
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action) {
+ READWRITE(nSatoshisPerK);
+ }
+};
+
+#endif // BITCOIN_POLICY_FEERATE_H
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index 5407aefb45..8056f385ab 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -7,46 +7,210 @@
#include "policy/policy.h"
#include "amount.h"
+#include "clientversion.h"
#include "primitives/transaction.h"
#include "random.h"
#include "streams.h"
#include "txmempool.h"
#include "util.h"
-void TxConfirmStats::Initialize(std::vector<double>& defaultBuckets,
- unsigned int maxConfirms, double _decay)
+static constexpr double INF_FEERATE = 1e99;
+
+std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon) {
+ static const std::map<FeeEstimateHorizon, std::string> horizon_strings = {
+ {FeeEstimateHorizon::SHORT_HALFLIFE, "short"},
+ {FeeEstimateHorizon::MED_HALFLIFE, "medium"},
+ {FeeEstimateHorizon::LONG_HALFLIFE, "long"},
+ };
+ auto horizon_string = horizon_strings.find(horizon);
+
+ if (horizon_string == horizon_strings.end()) return "unknown";
+
+ return horizon_string->second;
+}
+
+std::string StringForFeeReason(FeeReason reason) {
+ static const std::map<FeeReason, std::string> fee_reason_strings = {
+ {FeeReason::NONE, "None"},
+ {FeeReason::HALF_ESTIMATE, "Half Target 60% Threshold"},
+ {FeeReason::FULL_ESTIMATE, "Target 85% Threshold"},
+ {FeeReason::DOUBLE_ESTIMATE, "Double Target 95% Threshold"},
+ {FeeReason::CONSERVATIVE, "Conservative Double Target longer horizon"},
+ {FeeReason::MEMPOOL_MIN, "Mempool Min Fee"},
+ {FeeReason::PAYTXFEE, "PayTxFee set"},
+ {FeeReason::FALLBACK, "Fallback fee"},
+ {FeeReason::REQUIRED, "Minimum Required Fee"},
+ {FeeReason::MAXTXFEE, "MaxTxFee limit"}
+ };
+ auto reason_string = fee_reason_strings.find(reason);
+
+ if (reason_string == fee_reason_strings.end()) return "Unknown";
+
+ return reason_string->second;
+}
+
+bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode) {
+ static const std::map<std::string, FeeEstimateMode> fee_modes = {
+ {"UNSET", FeeEstimateMode::UNSET},
+ {"ECONOMICAL", FeeEstimateMode::ECONOMICAL},
+ {"CONSERVATIVE", FeeEstimateMode::CONSERVATIVE},
+ };
+ auto mode = fee_modes.find(mode_string);
+
+ if (mode == fee_modes.end()) return false;
+
+ fee_estimate_mode = mode->second;
+ return true;
+}
+
+/**
+ * We will instantiate an instance of this class to track transactions that were
+ * included in a block. We will lump transactions into a bucket according to their
+ * approximate feerate 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
+ const std::vector<double>& buckets; // The upper-bound of the range for the bucket (inclusive)
+ const 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;
+
+ // 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]
+
+ // Track moving avg of txs which have been evicted from the mempool
+ // after failing to be confirmed within Y blocks
+ std::vector<std::vector<double>> failAvg; // failAvg[Y][X]
+
+ // Sum the total feerate of all tx's in each bucket
+ // Track the historical moving average of this total over blocks
+ std::vector<double> avg;
+
+ // 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 feerate per bucket
+
+ double decay;
+
+ // Resolution (# of blocks) with which confirmations are tracked
+ unsigned int scale;
+
+ // 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 GetMaxConfirms for each bucket
+ std::vector<int> oldUnconfTxs;
+
+ void resizeInMemoryCounters(size_t newbuckets);
+
+public:
+ /**
+ * Create new TxConfirmStats. This is called by BlockPolicyEstimator's
+ * constructor with default values.
+ * @param defaultBuckets contains the upper limits for the bucket boundaries
+ * @param maxPeriods max number of periods to track
+ * @param decay how much to decay the historical moving average per block
+ */
+ TxConfirmStats(const std::vector<double>& defaultBuckets, const std::map<double, unsigned int>& defaultBucketMap,
+ unsigned int maxPeriods, double decay, unsigned int scale);
+
+ /** Roll the circular buffer for unconfirmed txs*/
+ 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 the feerate 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, bool inBlock);
+
+ /** Update our estimates by decaying our historical moving average and updating
+ with the data gathered from the current block */
+ void UpdateMovingAverages();
+
+ /**
+ * Calculate a feerate 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 feerate such that all higher values pass minSuccess OR
+ * return the highest feerate 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,
+ EstimationResult *result = nullptr) const;
+
+ /** Return the max number of confirms we're tracking */
+ unsigned int GetMaxConfirms() const { return scale * confAvg.size(); }
+
+ /** Write state of estimation data to a file*/
+ void Write(CAutoFile& fileout) const;
+
+ /**
+ * Read saved state of estimation data from a file and replace all internal data structures and
+ * variables with this state.
+ */
+ void Read(CAutoFile& filein, int nFileVersion, size_t numBuckets);
+};
+
+
+TxConfirmStats::TxConfirmStats(const std::vector<double>& defaultBuckets,
+ const std::map<double, unsigned int>& defaultBucketMap,
+ unsigned int maxPeriods, double _decay, unsigned int _scale)
+ : buckets(defaultBuckets), bucketMap(defaultBucketMap)
{
decay = _decay;
- 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++) {
+ scale = _scale;
+ confAvg.resize(maxPeriods);
+ for (unsigned int i = 0; i < maxPeriods; i++) {
confAvg[i].resize(buckets.size());
- curBlockConf[i].resize(buckets.size());
- unconfTxs[i].resize(buckets.size());
+ }
+ failAvg.resize(maxPeriods);
+ for (unsigned int i = 0; i < maxPeriods; i++) {
+ failAvg[i].resize(buckets.size());
}
- oldUnconfTxs.resize(buckets.size());
- curBlockTxCt.resize(buckets.size());
txCtAvg.resize(buckets.size());
- curBlockVal.resize(buckets.size());
avg.resize(buckets.size());
+
+ resizeInMemoryCounters(buckets.size());
+}
+
+void TxConfirmStats::resizeInMemoryCounters(size_t newbuckets) {
+ // newbuckets must be passed in because the buckets referred to during Read have not been updated yet.
+ unconfTxs.resize(GetMaxConfirms());
+ for (unsigned int i = 0; i < unconfTxs.size(); i++) {
+ unconfTxs[i].resize(newbuckets);
+ }
+ oldUnconfTxs.resize(newbuckets);
}
-// Zero out the data for the current block
+// Roll the unconfirmed txs circular buffer
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;
}
}
@@ -56,33 +220,38 @@ void TxConfirmStats::Record(int blocksToConfirm, double val)
// blocksToConfirm is 1-based
if (blocksToConfirm < 1)
return;
+ int periodsToConfirm = (blocksToConfirm + scale - 1)/scale;
unsigned int bucketindex = bucketMap.lower_bound(val)->second;
- for (size_t i = blocksToConfirm; i <= curBlockConf.size(); i++) {
- curBlockConf[i - 1][bucketindex]++;
+ for (size_t i = periodsToConfirm; i <= confAvg.size(); i++) {
+ confAvg[i - 1][bucketindex]++;
}
- curBlockTxCt[bucketindex]++;
- curBlockVal[bucketindex] += val;
+ txCtAvg[bucketindex]++;
+ avg[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];
+ confAvg[i][j] = confAvg[i][j] * decay;
+ for (unsigned int i = 0; i < failAvg.size(); i++)
+ failAvg[i][j] = failAvg[i][j] * decay;
+ avg[j] = avg[j] * decay;
+ txCtAvg[j] = txCtAvg[j] * decay;
}
}
// returns -1 on error conditions
double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
double successBreakPoint, bool requireGreater,
- unsigned int nBlockHeight)
+ unsigned int nBlockHeight, EstimationResult *result) const
{
// 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
+ double failNum = 0; // Number of tx's that were never confirmed but removed from the mempool after confTarget
+ int periodTarget = (confTarget + scale - 1)/scale;
int maxbucketindex = buckets.size() - 1;
@@ -105,12 +274,21 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
bool foundAnswer = false;
unsigned int bins = unconfTxs.size();
+ bool newBucketRange = true;
+ bool passing = true;
+ EstimatorBucket passBucket;
+ EstimatorBucket failBucket;
// Start counting from highest(default) or lowest feerate transactions
for (int bucket = startbucket; bucket >= 0 && bucket <= maxbucketindex; bucket += step) {
+ if (newBucketRange) {
+ curNearBucket = bucket;
+ newBucketRange = false;
+ }
curFarBucket = bucket;
- nConf += confAvg[confTarget - 1][bucket];
+ nConf += confAvg[periodTarget - 1][bucket];
totalNum += txCtAvg[bucket];
+ failNum += failAvg[periodTarget - 1][bucket];
for (unsigned int confct = confTarget; confct < GetMaxConfirms(); confct++)
extraNum += unconfTxs[(nBlockHeight - confct)%bins][bucket];
extraNum += oldUnconfTxs[bucket];
@@ -119,24 +297,41 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
// (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);
+ double curPct = nConf / (totalNum + failNum + 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;
-
+ if ((requireGreater && curPct < successBreakPoint) || (!requireGreater && curPct > successBreakPoint)) {
+ if (passing == true) {
+ // First time we hit a failure record the failed bucket
+ unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
+ unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
+ failBucket.start = failMinBucket ? buckets[failMinBucket - 1] : 0;
+ failBucket.end = buckets[failMaxBucket];
+ failBucket.withinTarget = nConf;
+ failBucket.totalConfirmed = totalNum;
+ failBucket.inMempool = extraNum;
+ failBucket.leftMempool = failNum;
+ passing = false;
+ }
+ continue;
+ }
// Otherwise update the cumulative stats, and the bucket variables
// and reset the counters
else {
+ failBucket = EstimatorBucket(); // Reset any failed bucket, currently passing
foundAnswer = true;
+ passing = true;
+ passBucket.withinTarget = nConf;
nConf = 0;
+ passBucket.totalConfirmed = totalNum;
totalNum = 0;
+ passBucket.inMempool = extraNum;
+ passBucket.leftMempool = failNum;
+ failNum = 0;
extraNum = 0;
bestNearBucket = curNearBucket;
bestFarBucket = curFarBucket;
- curNearBucket = bucket + step;
+ newBucketRange = true;
}
}
}
@@ -148,8 +343,8 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
// Find the bucket with the median transaction and then report the average feerate 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;
+ unsigned int minBucket = std::min(bestNearBucket, bestFarBucket);
+ unsigned int maxBucket = std::max(bestNearBucket, bestFarBucket);
for (unsigned int j = minBucket; j <= maxBucket; j++) {
txSum += txCtAvg[j];
}
@@ -163,85 +358,111 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
break;
}
}
+
+ passBucket.start = minBucket ? buckets[minBucket-1] : 0;
+ passBucket.end = buckets[maxBucket];
}
- LogPrint("estimatefee", "%3d: For conf success %s %4.2f need feerate %s: %12.5g from buckets %8g - %8g Cur Bucket stats %6.2f%% %8.1f/(%.1f+%d mempool)\n",
- confTarget, requireGreater ? ">" : "<", successBreakPoint,
- requireGreater ? ">" : "<", median, buckets[minBucket], buckets[maxBucket],
- 100 * nConf / (totalNum + extraNum), nConf, totalNum, extraNum);
+ // If we were passing until we reached last few buckets with insufficient data, then report those as failed
+ if (passing && !newBucketRange) {
+ unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
+ unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
+ failBucket.start = failMinBucket ? buckets[failMinBucket - 1] : 0;
+ failBucket.end = buckets[failMaxBucket];
+ failBucket.withinTarget = nConf;
+ failBucket.totalConfirmed = totalNum;
+ failBucket.inMempool = extraNum;
+ failBucket.leftMempool = failNum;
+ }
+ LogPrint(BCLog::ESTIMATEFEE, "FeeEst: %d %s%.0f%% decay %.5f: feerate: %g from (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n",
+ confTarget, requireGreater ? ">" : "<", 100.0 * successBreakPoint, decay,
+ median, passBucket.start, passBucket.end,
+ 100 * passBucket.withinTarget / (passBucket.totalConfirmed + passBucket.inMempool + passBucket.leftMempool),
+ passBucket.withinTarget, passBucket.totalConfirmed, passBucket.inMempool, passBucket.leftMempool,
+ failBucket.start, failBucket.end,
+ 100 * failBucket.withinTarget / (failBucket.totalConfirmed + failBucket.inMempool + failBucket.leftMempool),
+ failBucket.withinTarget, failBucket.totalConfirmed, failBucket.inMempool, failBucket.leftMempool);
+
+
+ if (result) {
+ result->pass = passBucket;
+ result->fail = failBucket;
+ result->decay = decay;
+ result->scale = scale;
+ }
return median;
}
-void TxConfirmStats::Write(CAutoFile& fileout)
+void TxConfirmStats::Write(CAutoFile& fileout) const
{
fileout << decay;
- fileout << buckets;
+ fileout << scale;
fileout << avg;
fileout << txCtAvg;
fileout << confAvg;
+ fileout << failAvg;
}
-void TxConfirmStats::Read(CAutoFile& filein)
+void TxConfirmStats::Read(CAutoFile& filein, int nFileVersion, size_t numBuckets)
{
- // 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 feerate buckets");
- filein >> fileAvg;
- if (fileAvg.size() != numBuckets)
+ // Read data file and do some very basic sanity checking
+ // buckets and bucketMap are not updated yet, so don't access them
+ // If there is a read failure, we'll just discard this entire object anyway
+ size_t maxConfirms, maxPeriods;
+
+ // The current version will store the decay with each individual TxConfirmStats and also keep a scale factor
+ if (nFileVersion >= 149900) {
+ filein >> decay;
+ if (decay <= 0 || decay >= 1) {
+ throw std::runtime_error("Corrupt estimates file. Decay must be between 0 and 1 (non-inclusive)");
+ }
+ filein >> scale;
+ }
+
+ filein >> avg;
+ if (avg.size() != numBuckets) {
throw std::runtime_error("Corrupt estimates file. Mismatch in feerate average bucket count");
- filein >> fileTxCtAvg;
- if (fileTxCtAvg.size() != numBuckets)
+ }
+ filein >> txCtAvg;
+ if (txCtAvg.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 feerate conf average bucket count");
}
- // Now that we've processed the entire feerate 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();
+ filein >> confAvg;
+ maxPeriods = confAvg.size();
+ maxConfirms = scale * maxPeriods;
- // 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());
+ 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 < maxPeriods; i++) {
+ if (confAvg[i].size() != numBuckets) {
+ throw std::runtime_error("Corrupt estimates file. Mismatch in feerate conf average bucket count");
+ }
}
- curBlockTxCt.resize(buckets.size());
- curBlockVal.resize(buckets.size());
- unconfTxs.resize(maxConfirms);
- for (unsigned int i = 0; i < maxConfirms; i++) {
- unconfTxs[i].resize(buckets.size());
+ if (nFileVersion >= 149900) {
+ filein >> failAvg;
+ if (maxPeriods != failAvg.size()) {
+ throw std::runtime_error("Corrupt estimates file. Mismatch in confirms tracked for failures");
+ }
+ for (unsigned int i = 0; i < maxPeriods; i++) {
+ if (failAvg[i].size() != numBuckets) {
+ throw std::runtime_error("Corrupt estimates file. Mismatch in one of failure average bucket counts");
+ }
+ }
+ } else {
+ failAvg.resize(confAvg.size());
+ for (unsigned int i = 0; i < failAvg.size(); i++) {
+ failAvg[i].resize(numBuckets);
+ }
}
- oldUnconfTxs.resize(buckets.size());
- for (unsigned int i = 0; i < buckets.size(); i++)
- bucketMap[buckets[i]] = i;
+ // Resize the current block variables which aren't stored in the data file
+ // to match the number of confirms and buckets
+ resizeInMemoryCounters(numBuckets);
- LogPrint("estimatefee", "Reading estimates: %u buckets counting confirms up to %u blocks\n",
+ LogPrint(BCLog::ESTIMATEFEE, "Reading estimates: %u buckets counting confirms up to %u blocks\n",
numBuckets, maxConfirms);
}
@@ -253,31 +474,39 @@ unsigned int TxConfirmStats::NewTx(unsigned int nBlockHeight, double val)
return bucketindex;
}
-void TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHeight, unsigned int bucketindex)
+void TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHeight, unsigned int bucketindex, bool inBlock)
{
//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");
+ LogPrint(BCLog::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)
+ if (oldUnconfTxs[bucketindex] > 0) {
oldUnconfTxs[bucketindex]--;
- else
- LogPrint("estimatefee", "Blockpolicy error, mempool tx removed from >25 blocks,bucketIndex=%u already\n",
+ } else {
+ LogPrint(BCLog::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)
+ if (unconfTxs[blockIndex][bucketindex] > 0) {
unconfTxs[blockIndex][bucketindex]--;
- else
- LogPrint("estimatefee", "Blockpolicy error, mempool tx removed from blockIndex=%u,bucketIndex=%u already\n",
+ } else {
+ LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error, mempool tx removed from blockIndex=%u,bucketIndex=%u already\n",
blockIndex, bucketindex);
+ }
+ }
+ if (!inBlock && (unsigned int)blocksAgo >= scale) { // Only counts as a failure if not confirmed for entire period
+ unsigned int periodsAgo = blocksAgo / scale;
+ for (size_t i = 0; i < periodsAgo && i < failAvg.size(); i++) {
+ failAvg[i][bucketindex]++;
+ }
}
}
@@ -286,11 +515,14 @@ void TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHe
// tracked. Txs that were part of a block have already been removed in
// processBlockTx to ensure they are never double tracked, but it is
// of no harm to try to remove them again.
-bool CBlockPolicyEstimator::removeTx(uint256 hash)
+bool CBlockPolicyEstimator::removeTx(uint256 hash, bool inBlock)
{
+ LOCK(cs_feeEstimator);
std::map<uint256, TxStatsInfo>::iterator pos = mapMemPoolTxs.find(hash);
if (pos != mapMemPoolTxs.end()) {
- feeStats.removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex);
+ feeStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
+ shortStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
+ longStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
mapMemPoolTxs.erase(hash);
return true;
} else {
@@ -298,25 +530,38 @@ bool CBlockPolicyEstimator::removeTx(uint256 hash)
}
}
-CBlockPolicyEstimator::CBlockPolicyEstimator(const CFeeRate& _minRelayFee)
- : nBestSeenHeight(0), trackedTxs(0), untrackedTxs(0)
+CBlockPolicyEstimator::CBlockPolicyEstimator()
+ : nBestSeenHeight(0), firstRecordedHeight(0), historicalFirst(0), historicalBest(0), trackedTxs(0), untrackedTxs(0)
{
- static_assert(MIN_FEERATE > 0, "Min feerate must be nonzero");
- 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);
+ static_assert(MIN_BUCKET_FEERATE > 0, "Min feerate must be nonzero");
+ size_t bucketIndex = 0;
+ for (double bucketBoundary = MIN_BUCKET_FEERATE; bucketBoundary <= MAX_BUCKET_FEERATE; bucketBoundary *= FEE_SPACING, bucketIndex++) {
+ buckets.push_back(bucketBoundary);
+ bucketMap[bucketBoundary] = bucketIndex;
}
- vfeelist.push_back(INF_FEERATE);
- feeStats.Initialize(vfeelist, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY);
+ buckets.push_back(INF_FEERATE);
+ bucketMap[INF_FEERATE] = bucketIndex;
+ assert(bucketMap.size() == buckets.size());
+
+ feeStats = new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE);
+ shortStats = new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE);
+ longStats = new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE);
+}
+
+CBlockPolicyEstimator::~CBlockPolicyEstimator()
+{
+ delete feeStats;
+ delete shortStats;
+ delete longStats;
}
void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate)
{
+ LOCK(cs_feeEstimator);
unsigned int txHeight = entry.GetHeight();
uint256 hash = entry.GetTx().GetHash();
if (mapMemPoolTxs.count(hash)) {
- LogPrint("estimatefee", "Blockpolicy error mempool tx %s already being tracked\n",
+ LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error mempool tx %s already being tracked\n",
hash.ToString().c_str());
return;
}
@@ -341,12 +586,17 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo
CFeeRate feeRate(entry.GetFee(), entry.GetTxSize());
mapMemPoolTxs[hash].blockHeight = txHeight;
- mapMemPoolTxs[hash].bucketIndex = feeStats.NewTx(txHeight, (double)feeRate.GetFeePerK());
+ unsigned int bucketIndex = feeStats->NewTx(txHeight, (double)feeRate.GetFeePerK());
+ mapMemPoolTxs[hash].bucketIndex = bucketIndex;
+ unsigned int bucketIndex2 = shortStats->NewTx(txHeight, (double)feeRate.GetFeePerK());
+ assert(bucketIndex == bucketIndex2);
+ unsigned int bucketIndex3 = longStats->NewTx(txHeight, (double)feeRate.GetFeePerK());
+ assert(bucketIndex == bucketIndex3);
}
bool CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry)
{
- if (!removeTx(entry->GetTx().GetHash())) {
+ if (!removeTx(entry->GetTx().GetHash(), true)) {
// This transaction wasn't being tracked for fee estimation
return false;
}
@@ -358,20 +608,23 @@ bool CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxM
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");
+ LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error Transaction had negative blocksToConfirm\n");
return false;
}
// Feerates are stored and reported as BTC-per-kb:
CFeeRate feeRate(entry->GetFee(), entry->GetTxSize());
- feeStats.Record(blocksToConfirm, (double)feeRate.GetFeePerK());
+ feeStats->Record(blocksToConfirm, (double)feeRate.GetFeePerK());
+ shortStats->Record(blocksToConfirm, (double)feeRate.GetFeePerK());
+ longStats->Record(blocksToConfirm, (double)feeRate.GetFeePerK());
return true;
}
void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
std::vector<const CTxMemPoolEntry*>& entries)
{
+ LOCK(cs_feeEstimator);
if (nBlockHeight <= nBestSeenHeight) {
// Ignore side chains and re-orgs; assuming they are random
// they don't affect the estimate.
@@ -386,113 +639,400 @@ void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
// of unconfirmed txs to remove from tracking.
nBestSeenHeight = nBlockHeight;
- // Clear the current block state and update unconfirmed circular buffer
- feeStats.ClearCurrent(nBlockHeight);
+ // Update unconfirmed circular buffer
+ feeStats->ClearCurrent(nBlockHeight);
+ shortStats->ClearCurrent(nBlockHeight);
+ longStats->ClearCurrent(nBlockHeight);
+
+ // Decay all exponential averages
+ feeStats->UpdateMovingAverages();
+ shortStats->UpdateMovingAverages();
+ longStats->UpdateMovingAverages();
unsigned int countedTxs = 0;
- // Repopulate the current block states
- for (unsigned int i = 0; i < entries.size(); i++) {
- if (processBlockTx(nBlockHeight, entries[i]))
+ // Update averages with data points from current block
+ for (const auto& entry : entries) {
+ if (processBlockTx(nBlockHeight, entry))
countedTxs++;
}
- // Update all exponential averages with the current block state
- feeStats.UpdateMovingAverages();
+ if (firstRecordedHeight == 0 && countedTxs > 0) {
+ firstRecordedHeight = nBestSeenHeight;
+ LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy first recorded height %u\n", firstRecordedHeight);
+ }
+
- LogPrint("estimatefee", "Blockpolicy after updating estimates for %u of %u txs in block, since last block %u of %u tracked, new mempool map size %u\n",
- countedTxs, entries.size(), trackedTxs, trackedTxs + untrackedTxs, mapMemPoolTxs.size());
+ LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy estimates updated by %u of %u block txs, since last block %u of %u tracked, mempool map size %u, max target %u from %s\n",
+ countedTxs, entries.size(), trackedTxs, trackedTxs + untrackedTxs, mapMemPoolTxs.size(),
+ MaxUsableEstimate(), HistoricalBlockSpan() > BlockSpan() ? "historical" : "current");
trackedTxs = 0;
untrackedTxs = 0;
}
-CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget)
+CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget) const
{
- // Return failure if trying to analyze a target we're not tracking
// It's not possible to get reasonable estimates for confTarget of 1
- if (confTarget <= 1 || (unsigned int)confTarget > feeStats.GetMaxConfirms())
+ if (confTarget <= 1)
+ return CFeeRate(0);
+
+ return estimateRawFee(confTarget, DOUBLE_SUCCESS_PCT, FeeEstimateHorizon::MED_HALFLIFE);
+}
+
+CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThreshold, FeeEstimateHorizon horizon, EstimationResult* result) const
+{
+ TxConfirmStats* stats;
+ double sufficientTxs = SUFFICIENT_FEETXS;
+ switch (horizon) {
+ case FeeEstimateHorizon::SHORT_HALFLIFE: {
+ stats = shortStats;
+ sufficientTxs = SUFFICIENT_TXS_SHORT;
+ break;
+ }
+ case FeeEstimateHorizon::MED_HALFLIFE: {
+ stats = feeStats;
+ break;
+ }
+ case FeeEstimateHorizon::LONG_HALFLIFE: {
+ stats = longStats;
+ break;
+ }
+ default: {
+ throw std::out_of_range("CBlockPolicyEstimator::estimateRawFee unknown FeeEstimateHorizon");
+ }
+ }
+
+ LOCK(cs_feeEstimator);
+ // Return failure if trying to analyze a target we're not tracking
+ if (confTarget <= 0 || (unsigned int)confTarget > stats->GetMaxConfirms())
+ return CFeeRate(0);
+ if (successThreshold > 1)
return CFeeRate(0);
- double median = feeStats.EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBestSeenHeight);
+ double median = stats->EstimateMedianVal(confTarget, sufficientTxs, successThreshold, true, nBestSeenHeight, result);
if (median < 0)
return CFeeRate(0);
- return CFeeRate(median);
+ return CFeeRate(llround(median));
}
-CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool)
+unsigned int CBlockPolicyEstimator::HighestTargetTracked(FeeEstimateHorizon horizon) const
{
- if (answerFoundAtTarget)
- *answerFoundAtTarget = confTarget;
- // Return failure if trying to analyze a target we're not tracking
- if (confTarget <= 0 || (unsigned int)confTarget > feeStats.GetMaxConfirms())
- return CFeeRate(0);
+ switch (horizon) {
+ case FeeEstimateHorizon::SHORT_HALFLIFE: {
+ return shortStats->GetMaxConfirms();
+ }
+ case FeeEstimateHorizon::MED_HALFLIFE: {
+ return feeStats->GetMaxConfirms();
+ }
+ case FeeEstimateHorizon::LONG_HALFLIFE: {
+ return longStats->GetMaxConfirms();
+ }
+ default: {
+ throw std::out_of_range("CBlockPolicyEstimator::HighestTargetTracked unknown FeeEstimateHorizon");
+ }
+ }
+}
- // It's not possible to get reasonable estimates for confTarget of 1
- if (confTarget == 1)
- confTarget = 2;
+unsigned int CBlockPolicyEstimator::BlockSpan() const
+{
+ if (firstRecordedHeight == 0) return 0;
+ assert(nBestSeenHeight >= firstRecordedHeight);
- double median = -1;
- while (median < 0 && (unsigned int)confTarget <= feeStats.GetMaxConfirms()) {
- median = feeStats.EstimateMedianVal(confTarget++, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBestSeenHeight);
- }
+ return nBestSeenHeight - firstRecordedHeight;
+}
- if (answerFoundAtTarget)
- *answerFoundAtTarget = confTarget - 1;
+unsigned int CBlockPolicyEstimator::HistoricalBlockSpan() const
+{
+ if (historicalFirst == 0) return 0;
+ assert(historicalBest >= historicalFirst);
- // If mempool is limiting txs , return at least the min feerate from the mempool
- CAmount minPoolFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK();
- if (minPoolFee > 0 && minPoolFee > median)
- return CFeeRate(minPoolFee);
+ if (nBestSeenHeight - historicalBest > OLDEST_ESTIMATE_HISTORY) return 0;
- if (median < 0)
- return CFeeRate(0);
+ return historicalBest - historicalFirst;
+}
- return CFeeRate(median);
+unsigned int CBlockPolicyEstimator::MaxUsableEstimate() const
+{
+ // Block spans are divided by 2 to make sure there are enough potential failing data points for the estimate
+ return std::min(longStats->GetMaxConfirms(), std::max(BlockSpan(), HistoricalBlockSpan()) / 2);
}
-double CBlockPolicyEstimator::estimatePriority(int confTarget)
+/** Return a fee estimate at the required successThreshold from the shortest
+ * time horizon which tracks confirmations up to the desired target. If
+ * checkShorterHorizon is requested, also allow short time horizon estimates
+ * for a lower target to reduce the given answer */
+double CBlockPolicyEstimator::estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon, EstimationResult *result) const
{
- return -1;
+ double estimate = -1;
+ if (confTarget >= 1 && confTarget <= longStats->GetMaxConfirms()) {
+ // Find estimate from shortest time horizon possible
+ if (confTarget <= shortStats->GetMaxConfirms()) { // short horizon
+ estimate = shortStats->EstimateMedianVal(confTarget, SUFFICIENT_TXS_SHORT, successThreshold, true, nBestSeenHeight, result);
+ }
+ else if (confTarget <= feeStats->GetMaxConfirms()) { // medium horizon
+ estimate = feeStats->EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, successThreshold, true, nBestSeenHeight, result);
+ }
+ else { // long horizon
+ estimate = longStats->EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, successThreshold, true, nBestSeenHeight, result);
+ }
+ if (checkShorterHorizon) {
+ EstimationResult tempResult;
+ // If a lower confTarget from a more recent horizon returns a lower answer use it.
+ if (confTarget > feeStats->GetMaxConfirms()) {
+ double medMax = feeStats->EstimateMedianVal(feeStats->GetMaxConfirms(), SUFFICIENT_FEETXS, successThreshold, true, nBestSeenHeight, &tempResult);
+ if (medMax > 0 && (estimate == -1 || medMax < estimate)) {
+ estimate = medMax;
+ if (result) *result = tempResult;
+ }
+ }
+ if (confTarget > shortStats->GetMaxConfirms()) {
+ double shortMax = shortStats->EstimateMedianVal(shortStats->GetMaxConfirms(), SUFFICIENT_TXS_SHORT, successThreshold, true, nBestSeenHeight, &tempResult);
+ if (shortMax > 0 && (estimate == -1 || shortMax < estimate)) {
+ estimate = shortMax;
+ if (result) *result = tempResult;
+ }
+ }
+ }
+ }
+ return estimate;
}
-double CBlockPolicyEstimator::estimateSmartPriority(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool)
+/** Ensure that for a conservative estimate, the DOUBLE_SUCCESS_PCT is also met
+ * at 2 * target for any longer time horizons.
+ */
+double CBlockPolicyEstimator::estimateConservativeFee(unsigned int doubleTarget, EstimationResult *result) const
{
- if (answerFoundAtTarget)
- *answerFoundAtTarget = confTarget;
+ double estimate = -1;
+ EstimationResult tempResult;
+ if (doubleTarget <= shortStats->GetMaxConfirms()) {
+ estimate = feeStats->EstimateMedianVal(doubleTarget, SUFFICIENT_FEETXS, DOUBLE_SUCCESS_PCT, true, nBestSeenHeight, result);
+ }
+ if (doubleTarget <= feeStats->GetMaxConfirms()) {
+ double longEstimate = longStats->EstimateMedianVal(doubleTarget, SUFFICIENT_FEETXS, DOUBLE_SUCCESS_PCT, true, nBestSeenHeight, &tempResult);
+ if (longEstimate > estimate) {
+ estimate = longEstimate;
+ if (result) *result = tempResult;
+ }
+ }
+ return estimate;
+}
+
+/** estimateSmartFee returns the max of the feerates calculated with a 60%
+ * threshold required at target / 2, an 85% threshold required at target and a
+ * 95% threshold required at 2 * target. Each calculation is performed at the
+ * shortest time horizon which tracks the required target. Conservative
+ * estimates, however, required the 95% threshold at 2 * target be met for any
+ * longer time horizons also.
+ */
+CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation *feeCalc, bool conservative) const
+{
+ LOCK(cs_feeEstimator);
+
+ if (feeCalc) {
+ feeCalc->desiredTarget = confTarget;
+ feeCalc->returnedTarget = confTarget;
+ }
+
+ double median = -1;
+ EstimationResult tempResult;
- // If mempool is limiting txs, no priority txs are allowed
- CAmount minPoolFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK();
- if (minPoolFee > 0)
- return INF_PRIORITY;
+ // Return failure if trying to analyze a target we're not tracking
+ if (confTarget <= 0 || (unsigned int)confTarget > longStats->GetMaxConfirms()) {
+ return CFeeRate(0); // error condition
+ }
+
+ // It's not possible to get reasonable estimates for confTarget of 1
+ if (confTarget == 1) confTarget = 2;
+
+ unsigned int maxUsableEstimate = MaxUsableEstimate();
+ if ((unsigned int)confTarget > maxUsableEstimate) {
+ confTarget = maxUsableEstimate;
+ }
+ if (feeCalc) feeCalc->returnedTarget = confTarget;
+
+ if (confTarget <= 1) return CFeeRate(0); // error condition
+
+ assert(confTarget > 0); //estimateCombinedFee and estimateConservativeFee take unsigned ints
+ /** true is passed to estimateCombined fee for target/2 and target so
+ * that we check the max confirms for shorter time horizons as well.
+ * This is necessary to preserve monotonically increasing estimates.
+ * For non-conservative estimates we do the same thing for 2*target, but
+ * for conservative estimates we want to skip these shorter horizons
+ * checks for 2*target because we are taking the max over all time
+ * horizons so we already have monotonically increasing estimates and
+ * the purpose of conservative estimates is not to let short term
+ * fluctuations lower our estimates by too much.
+ */
+ double halfEst = estimateCombinedFee(confTarget/2, HALF_SUCCESS_PCT, true, &tempResult);
+ if (feeCalc) {
+ feeCalc->est = tempResult;
+ feeCalc->reason = FeeReason::HALF_ESTIMATE;
+ }
+ median = halfEst;
+ double actualEst = estimateCombinedFee(confTarget, SUCCESS_PCT, true, &tempResult);
+ if (actualEst > median) {
+ median = actualEst;
+ if (feeCalc) {
+ feeCalc->est = tempResult;
+ feeCalc->reason = FeeReason::FULL_ESTIMATE;
+ }
+ }
+ double doubleEst = estimateCombinedFee(2 * confTarget, DOUBLE_SUCCESS_PCT, !conservative, &tempResult);
+ if (doubleEst > median) {
+ median = doubleEst;
+ if (feeCalc) {
+ feeCalc->est = tempResult;
+ feeCalc->reason = FeeReason::DOUBLE_ESTIMATE;
+ }
+ }
- return -1;
+ if (conservative || median == -1) {
+ double consEst = estimateConservativeFee(2 * confTarget, &tempResult);
+ if (consEst > median) {
+ median = consEst;
+ if (feeCalc) {
+ feeCalc->est = tempResult;
+ feeCalc->reason = FeeReason::CONSERVATIVE;
+ }
+ }
+ }
+
+ if (median < 0) return CFeeRate(0); // error condition
+
+ return CFeeRate(llround(median));
}
-void CBlockPolicyEstimator::Write(CAutoFile& fileout)
+
+bool CBlockPolicyEstimator::Write(CAutoFile& fileout) const
{
- fileout << nBestSeenHeight;
- feeStats.Write(fileout);
+ try {
+ LOCK(cs_feeEstimator);
+ fileout << 149900; // version required to read: 0.14.99 or later
+ fileout << CLIENT_VERSION; // version that wrote the file
+ fileout << nBestSeenHeight;
+ if (BlockSpan() > HistoricalBlockSpan()/2) {
+ fileout << firstRecordedHeight << nBestSeenHeight;
+ }
+ else {
+ fileout << historicalFirst << historicalBest;
+ }
+ fileout << buckets;
+ feeStats->Write(fileout);
+ shortStats->Write(fileout);
+ longStats->Write(fileout);
+ }
+ catch (const std::exception&) {
+ LogPrintf("CBlockPolicyEstimator::Write(): unable to write policy estimator data (non-fatal)\n");
+ return false;
+ }
+ return true;
}
-void CBlockPolicyEstimator::Read(CAutoFile& filein, int nFileVersion)
+bool CBlockPolicyEstimator::Read(CAutoFile& filein)
{
- int nFileBestSeenHeight;
- filein >> nFileBestSeenHeight;
- feeStats.Read(filein);
- nBestSeenHeight = nFileBestSeenHeight;
- if (nFileVersion < 139900) {
- TxConfirmStats priStats;
- priStats.Read(filein);
+ try {
+ LOCK(cs_feeEstimator);
+ int nVersionRequired, nVersionThatWrote;
+ filein >> nVersionRequired >> nVersionThatWrote;
+ if (nVersionRequired > CLIENT_VERSION)
+ return error("CBlockPolicyEstimator::Read(): up-version (%d) fee estimate file", nVersionRequired);
+
+ // Read fee estimates file into temporary variables so existing data
+ // structures aren't corrupted if there is an exception.
+ unsigned int nFileBestSeenHeight;
+ filein >> nFileBestSeenHeight;
+
+ if (nVersionThatWrote < 149900) {
+ // Read the old fee estimates file for temporary use, but then discard. Will start collecting data from scratch.
+ // decay is stored before buckets in old versions, so pre-read decay and pass into TxConfirmStats constructor
+ double tempDecay;
+ filein >> tempDecay;
+ if (tempDecay <= 0 || tempDecay >= 1)
+ throw std::runtime_error("Corrupt estimates file. Decay must be between 0 and 1 (non-inclusive)");
+
+ std::vector<double> tempBuckets;
+ filein >> tempBuckets;
+ size_t tempNum = tempBuckets.size();
+ if (tempNum <= 1 || tempNum > 1000)
+ throw std::runtime_error("Corrupt estimates file. Must have between 2 and 1000 feerate buckets");
+
+ std::map<double, unsigned int> tempMap;
+
+ std::unique_ptr<TxConfirmStats> tempFeeStats(new TxConfirmStats(tempBuckets, tempMap, MED_BLOCK_PERIODS, tempDecay, 1));
+ tempFeeStats->Read(filein, nVersionThatWrote, tempNum);
+ // if nVersionThatWrote < 139900 then another TxConfirmStats (for priority) follows but can be ignored.
+
+ tempMap.clear();
+ for (unsigned int i = 0; i < tempBuckets.size(); i++) {
+ tempMap[tempBuckets[i]] = i;
+ }
+ }
+ else { // nVersionThatWrote >= 149900
+ unsigned int nFileHistoricalFirst, nFileHistoricalBest;
+ filein >> nFileHistoricalFirst >> nFileHistoricalBest;
+ if (nFileHistoricalFirst > nFileHistoricalBest || nFileHistoricalBest > nFileBestSeenHeight) {
+ throw std::runtime_error("Corrupt estimates file. Historical block range for estimates is invalid");
+ }
+ std::vector<double> fileBuckets;
+ filein >> fileBuckets;
+ size_t numBuckets = fileBuckets.size();
+ if (numBuckets <= 1 || numBuckets > 1000)
+ throw std::runtime_error("Corrupt estimates file. Must have between 2 and 1000 feerate buckets");
+
+ std::unique_ptr<TxConfirmStats> fileFeeStats(new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE));
+ std::unique_ptr<TxConfirmStats> fileShortStats(new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
+ std::unique_ptr<TxConfirmStats> fileLongStats(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
+ fileFeeStats->Read(filein, nVersionThatWrote, numBuckets);
+ fileShortStats->Read(filein, nVersionThatWrote, numBuckets);
+ fileLongStats->Read(filein, nVersionThatWrote, numBuckets);
+
+ // Fee estimates file parsed correctly
+ // Copy buckets from file and refresh our bucketmap
+ buckets = fileBuckets;
+ bucketMap.clear();
+ for (unsigned int i = 0; i < buckets.size(); i++) {
+ bucketMap[buckets[i]] = i;
+ }
+
+ // Destroy old TxConfirmStats and point to new ones that already reference buckets and bucketMap
+ delete feeStats;
+ delete shortStats;
+ delete longStats;
+ feeStats = fileFeeStats.release();
+ shortStats = fileShortStats.release();
+ longStats = fileLongStats.release();
+
+ nBestSeenHeight = nFileBestSeenHeight;
+ historicalFirst = nFileHistoricalFirst;
+ historicalBest = nFileHistoricalBest;
+ }
+ }
+ catch (const std::exception& e) {
+ LogPrintf("CBlockPolicyEstimator::Read(): unable to read policy estimator data (non-fatal): %s\n",e.what());
+ return false;
+ }
+ return true;
+}
+
+void CBlockPolicyEstimator::FlushUnconfirmed(CTxMemPool& pool) {
+ int64_t startclear = GetTimeMicros();
+ std::vector<uint256> txids;
+ pool.queryHashes(txids);
+ LOCK(cs_feeEstimator);
+ for (auto& txid : txids) {
+ removeTx(txid, false);
}
+ int64_t endclear = GetTimeMicros();
+ LogPrint(BCLog::ESTIMATEFEE, "Recorded %u unconfirmed txs from mempool in %gs\n",txids.size(), (endclear - startclear)*0.000001);
}
FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee)
{
CAmount minFeeLimit = std::max(CAmount(1), minIncrementalFee.GetFeePerK() / 2);
feeset.insert(0);
- for (double bucketBoundary = minFeeLimit; bucketBoundary <= MAX_FEERATE; bucketBoundary *= FEE_SPACING) {
+ for (double bucketBoundary = minFeeLimit; bucketBoundary <= MAX_FILTER_FEERATE; bucketBoundary *= FEE_FILTER_SPACING) {
feeset.insert(bucketBoundary);
}
}
@@ -503,5 +1043,5 @@ CAmount FeeFilterRounder::round(CAmount currentMinFee)
if ((it != feeset.begin() && insecure_rand.rand32() % 3 != 0) || it == feeset.end()) {
it--;
}
- return *it;
+ return static_cast<CAmount>(*it);
}
diff --git a/src/policy/fees.h b/src/policy/fees.h
index 064466afe4..6edaf28714 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -6,8 +6,10 @@
#define BITCOIN_POLICYESTIMATOR_H
#include "amount.h"
+#include "feerate.h"
#include "uint256.h"
#include "random.h"
+#include "sync.h"
#include <map>
#include <string>
@@ -17,6 +19,7 @@ class CAutoFile;
class CFeeRate;
class CTxMemPoolEntry;
class CTxMemPool;
+class TxConfirmStats;
/** \class CBlockPolicyEstimator
* The BlockPolicyEstimator is used for estimating the feerate needed
@@ -39,156 +42,92 @@ class CTxMemPool;
* within your desired 5 blocks.
*
* Here is a brief description of the implementation:
- * When a transaction 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 feerate
- * 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 feerate
- * 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 feerate bucket when calculating
- * an estimate for any number of confirmations below the number of blocks
- * they've been outstanding.
+ * When a transaction enters the mempool, we track the height of the block chain
+ * at entry. All further calculations are conducted only on this set of "seen"
+ * transactions. Whenever a block comes in, we count the number of transactions
+ * in each bucket and the total amount of feerate paid in each bucket. Then we
+ * calculate how many blocks Y it took each transaction to be mined. We convert
+ * from a number of blocks to a number of periods Y' each encompassing "scale"
+ * blocks. This is tracked in 3 different data sets each up to a maximum
+ * number of periods. Within each data set we have an array of counters in each
+ * feerate bucket and we increment all the counters from Y' up to max periods
+ * representing that a tx was successfully confirmed in less than or equal to
+ * that many periods. 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 feerate bucket and the total number that were confirmed in each of the
+ * periods or less for any bucket. We save this history by keeping an
+ * exponentially decaying moving average of each one of these stats. This is
+ * done for a different decay in each of the 3 data sets to keep relevant data
+ * from different time horizons. Furthermore we also keep track of the number
+ * unmined (in mempool or left mempool without being included in a block)
+ * transactions in each bucket and for how many blocks they have been
+ * outstanding and use both of these numbers to increase the number of transactions
+ * we've seen in that feerate bucket when calculating an estimate for any number
+ * of confirmations below the number of blocks they've been outstanding.
*/
-/**
- * We will instantiate an instance of this class to track transactions that were
- * included in a block. We will lump transactions into a bucket according to their
- * approximate feerate 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
- 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 calculate 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 calculate the totals for the current block to update the moving averages
- std::vector<std::vector<int> > curBlockConf; // curBlockConf[Y][X]
-
- // Sum the total feerate 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 feerate per bucket
-
- 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
- */
- void Initialize(std::vector<double>& defaultBuckets, unsigned int maxConfirms, double decay);
-
- /** 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 the feerate 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 feerate 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 feerate such that all higher values pass minSuccess OR
- * return the highest feerate 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);
+/* Identifier for each of the 3 different TxConfirmStats which will track
+ * history over different time horizons. */
+enum FeeEstimateHorizon {
+ SHORT_HALFLIFE = 0,
+ MED_HALFLIFE = 1,
+ LONG_HALFLIFE = 2
};
+std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon);
+
+/* Enumeration of reason for returned fee estimate */
+enum class FeeReason {
+ NONE,
+ HALF_ESTIMATE,
+ FULL_ESTIMATE,
+ DOUBLE_ESTIMATE,
+ CONSERVATIVE,
+ MEMPOOL_MIN,
+ PAYTXFEE,
+ FALLBACK,
+ REQUIRED,
+ MAXTXFEE,
+};
+std::string StringForFeeReason(FeeReason reason);
-/** 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;
+/* Used to determine type of fee estimation requested */
+enum class FeeEstimateMode {
+ UNSET, //! Use default settings based on other criteria
+ ECONOMICAL, //! Force estimateSmartFee to use non-conservative estimates
+ CONSERVATIVE, //! Force estimateSmartFee to use conservative estimates
+};
-/** Require greater than 95% of X feerate transactions to be confirmed within Y blocks for X to be big enough */
-static const double MIN_SUCCESS_PCT = .95;
+bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode);
-/** Require an avg of 1 tx in the combined feerate bucket per block to have stat significance */
-static const double SUFFICIENT_FEETXS = 1;
+/* Used to return detailed information about a feerate bucket */
+struct EstimatorBucket
+{
+ double start = -1;
+ double end = -1;
+ double withinTarget = 0;
+ double totalConfirmed = 0;
+ double inMempool = 0;
+ double leftMempool = 0;
+};
-// Minimum and Maximum values for tracking feerates
-static constexpr double MIN_FEERATE = 10;
-static const double MAX_FEERATE = 1e7;
-static const double INF_FEERATE = MAX_MONEY;
-static const double INF_PRIORITY = 1e9 * MAX_MONEY;
+/* Used to return detailed information about a fee estimate calculation */
+struct EstimationResult
+{
+ EstimatorBucket pass;
+ EstimatorBucket fail;
+ double decay = 0;
+ unsigned int scale = 0;
+};
-// We have to lump transactions into buckets based on feerate, but we want to be able
-// to give accurate estimates over a large range of potential feerates
-// Therefore it makes sense to exponentially space the buckets
-/** Spacing of FeeRate buckets */
-static const double FEE_SPACING = 1.1;
+struct FeeCalculation
+{
+ EstimationResult est;
+ FeeReason reason = FeeReason::NONE;
+ int desiredTarget = 0;
+ int returnedTarget = 0;
+};
/**
* We want to be able to estimate feerates that are needed on tx's to be included in
@@ -197,55 +136,104 @@ static const double FEE_SPACING = 1.1;
*/
class CBlockPolicyEstimator
{
+private:
+ /** Track confirm delays up to 12 blocks for short horizon */
+ static constexpr unsigned int SHORT_BLOCK_PERIODS = 12;
+ static constexpr unsigned int SHORT_SCALE = 1;
+ /** Track confirm delays up to 48 blocks for medium horizon */
+ static constexpr unsigned int MED_BLOCK_PERIODS = 24;
+ static constexpr unsigned int MED_SCALE = 2;
+ /** Track confirm delays up to 1008 blocks for long horizon */
+ static constexpr unsigned int LONG_BLOCK_PERIODS = 42;
+ static constexpr unsigned int LONG_SCALE = 24;
+ /** Historical estimates that are older than this aren't valid */
+ static const unsigned int OLDEST_ESTIMATE_HISTORY = 6 * 1008;
+
+ /** Decay of .962 is a half-life of 18 blocks or about 3 hours */
+ static constexpr double SHORT_DECAY = .962;
+ /** Decay of .998 is a half-life of 144 blocks or about 1 day */
+ static constexpr double MED_DECAY = .9952;
+ /** Decay of .9995 is a half-life of 1008 blocks or about 1 week */
+ static constexpr double LONG_DECAY = .99931;
+
+ /** Require greater than 60% of X feerate transactions to be confirmed within Y/2 blocks*/
+ static constexpr double HALF_SUCCESS_PCT = .6;
+ /** Require greater than 85% of X feerate transactions to be confirmed within Y blocks*/
+ static constexpr double SUCCESS_PCT = .85;
+ /** Require greater than 95% of X feerate transactions to be confirmed within 2 * Y blocks*/
+ static constexpr double DOUBLE_SUCCESS_PCT = .95;
+
+ /** Require an avg of 0.1 tx in the combined feerate bucket per block to have stat significance */
+ static constexpr double SUFFICIENT_FEETXS = 0.1;
+ /** Require an avg of 0.5 tx when using short decay since there are fewer blocks considered*/
+ static constexpr double SUFFICIENT_TXS_SHORT = 0.5;
+
+ /** Minimum and Maximum values for tracking feerates
+ * The MIN_BUCKET_FEERATE should just be set to the lowest reasonable feerate we
+ * might ever want to track. Historically this has been 1000 since it was
+ * inheriting DEFAULT_MIN_RELAY_TX_FEE and changing it is disruptive as it
+ * invalidates old estimates files. So leave it at 1000 unless it becomes
+ * necessary to lower it, and then lower it substantially.
+ */
+ static constexpr double MIN_BUCKET_FEERATE = 1000;
+ static constexpr double MAX_BUCKET_FEERATE = 1e7;
+
+ /** Spacing of FeeRate buckets
+ * We have to lump transactions into buckets based on feerate, but we want to be able
+ * to give accurate estimates over a large range of potential feerates
+ * Therefore it makes sense to exponentially space the buckets
+ */
+ static constexpr double FEE_SPACING = 1.05;
+
public:
/** Create new BlockPolicyEstimator and initialize stats tracking classes with default values */
- CBlockPolicyEstimator(const CFeeRate& minRelayFee);
+ CBlockPolicyEstimator();
+ ~CBlockPolicyEstimator();
/** Process all the transactions that have been included in a block */
void processBlock(unsigned int nBlockHeight,
std::vector<const CTxMemPoolEntry*>& entries);
- /** Process a transaction confirmed in a block*/
- bool processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry);
-
/** Process a transaction accepted to the mempool*/
void processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate);
/** Remove a transaction from the mempool tracking stats*/
- bool removeTx(uint256 hash);
+ bool removeTx(uint256 hash, bool inBlock);
- /** Return a feerate estimate */
- CFeeRate estimateFee(int confTarget);
+ /** DEPRECATED. Return a feerate estimate */
+ CFeeRate estimateFee(int confTarget) const;
- /** Estimate feerate needed to get be included in a block within
- * confTarget blocks. If no answer can be given at confTarget, return an
- * estimate at the lowest target where one can be given.
+ /** Estimate feerate needed to get be included in a block within confTarget
+ * blocks. If no answer can be given at confTarget, return an estimate at
+ * the closest target where one can be given. 'conservative' estimates are
+ * valid over longer time horizons also.
*/
- CFeeRate estimateSmartFee(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool);
+ CFeeRate estimateSmartFee(int confTarget, FeeCalculation *feeCalc, bool conservative) const;
- /** Return a priority estimate.
- * DEPRECATED
- * Returns -1
+ /** Return a specific fee estimate calculation with a given success
+ * threshold and time horizon, and optionally return detailed data about
+ * calculation
*/
- double estimatePriority(int confTarget);
-
- /** Estimate priority needed to get be included in a block within
- * confTarget blocks.
- * DEPRECATED
- * Returns -1 unless mempool is currently limited then returns INF_PRIORITY
- * answerFoundAtTarget is set to confTarget
- */
- double estimateSmartPriority(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool);
+ CFeeRate estimateRawFee(int confTarget, double successThreshold, FeeEstimateHorizon horizon, EstimationResult *result = nullptr) const;
/** Write estimation data to a file */
- void Write(CAutoFile& fileout);
+ bool Write(CAutoFile& fileout) const;
/** Read estimation data from a file */
- void Read(CAutoFile& filein, int nFileVersion);
+ bool Read(CAutoFile& filein);
+
+ /** Empty mempool transactions on shutdown to record failure to confirm for txs still in mempool */
+ void FlushUnconfirmed(CTxMemPool& pool);
+
+ /** Calculation of highest target that estimates are tracked for */
+ unsigned int HighestTargetTracked(FeeEstimateHorizon horizon) const;
private:
- CFeeRate minTrackedFee; //!< Passed to constructor to avoid dependency on main
unsigned int nBestSeenHeight;
+ unsigned int firstRecordedHeight;
+ unsigned int historicalFirst;
+ unsigned int historicalBest;
+
struct TxStatsInfo
{
unsigned int blockHeight;
@@ -257,17 +245,46 @@ private:
std::map<uint256, TxStatsInfo> mapMemPoolTxs;
/** Classes to track historical data on transaction confirmations */
- TxConfirmStats feeStats;
+ TxConfirmStats* feeStats;
+ TxConfirmStats* shortStats;
+ TxConfirmStats* longStats;
unsigned int trackedTxs;
unsigned int untrackedTxs;
+
+ 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
+
+ mutable CCriticalSection cs_feeEstimator;
+
+ /** Process a transaction confirmed in a block*/
+ bool processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry);
+
+ /** Helper for estimateSmartFee */
+ double estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon, EstimationResult *result) const;
+ /** Helper for estimateSmartFee */
+ double estimateConservativeFee(unsigned int doubleTarget, EstimationResult *result) const;
+ /** Number of blocks of data recorded while fee estimates have been running */
+ unsigned int BlockSpan() const;
+ /** Number of blocks of recorded fee estimate data represented in saved data file */
+ unsigned int HistoricalBlockSpan() const;
+ /** Calculation of highest target that reasonable estimate can be provided for */
+ unsigned int MaxUsableEstimate() const;
};
class FeeFilterRounder
{
+private:
+ static constexpr double MAX_FILTER_FEERATE = 1e7;
+ /** FEE_FILTER_SPACING is just used to provide some quantization of fee
+ * filter results. Historically it reused FEE_SPACING, but it is completely
+ * unrelated, and was made a separate constant so the two concepts are not
+ * tied together */
+ static constexpr double FEE_FILTER_SPACING = 1.1;
+
public:
/** Create new FeeFilterRounder */
- FeeFilterRounder(const CFeeRate& minIncrementalFee);
+ explicit FeeFilterRounder(const CFeeRate& minIncrementalFee);
/** Quantize a minimum fee for privacy purpose before broadcast **/
CAmount round(CAmount currentMinFee);
@@ -276,4 +293,5 @@ private:
std::set<double> feeset;
FastRandomContext insecure_rand;
};
+
#endif /*BITCOIN_POLICYESTIMATOR_H */
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index ec398f6627..b2fb284508 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -7,29 +7,52 @@
#include "policy/policy.h"
+#include "consensus/validation.h"
#include "validation.h"
+#include "coins.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
- *
- * 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
- */
+
+CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
+{
+ // "Dust" is defined in terms of dustRelayFee,
+ // which has units satoshis-per-kilobyte.
+ // If you'd pay more in fees than the value of the output
+ // to spend something, then we consider it dust.
+ // A typical spendable non-segwit txout is 34 bytes big, and will
+ // need a CTxIn of at least 148 bytes to spend:
+ // so dust is a spendable txout less than
+ // 182*dustRelayFee/1000 (in satoshis).
+ // 546 satoshis at the default rate of 3000 sat/kB.
+ // A typical spendable segwit txout is 31 bytes big, and will
+ // need a CTxIn of at least 67 bytes to spend:
+ // so dust is a spendable txout less than
+ // 98*dustRelayFee/1000 (in satoshis).
+ // 294 satoshis at the default rate of 3000 sat/kB.
+ if (txout.scriptPubKey.IsUnspendable())
+ return 0;
+
+ size_t nSize = GetSerializeSize(txout, SER_DISK, 0);
+ int witnessversion = 0;
+ std::vector<unsigned char> witnessprogram;
+
+ if (txout.scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
+ // sum the sizes of the parts of a transaction input
+ // with 75% segwit discount applied to the script size.
+ nSize += (32 + 4 + 1 + (107 / WITNESS_SCALE_FACTOR) + 4);
+ } else {
+ nSize += (32 + 4 + 1 + 107 + 4); // the 148 mentioned above
+ }
+
+ return dustRelayFeeIn.GetFee(nSize);
+}
+
+bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
+{
+ return (txout.nValue < GetDustThreshold(txout, dustRelayFeeIn));
+}
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType, const bool witnessEnabled)
{
@@ -53,7 +76,7 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType, const bool w
else if (!witnessEnabled && (whichType == TX_WITNESS_V0_KEYHASH || whichType == TX_WITNESS_V0_SCRIPTHASH))
return false;
- return whichType != TX_NONSTANDARD;
+ return whichType != TX_NONSTANDARD && whichType != TX_WITNESS_UNKNOWN;
}
bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnessEnabled)
@@ -73,7 +96,7 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnes
return false;
}
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ for (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
@@ -94,7 +117,7 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnes
unsigned int nDataOut = 0;
txnouttype whichType;
- BOOST_FOREACH(const CTxOut& txout, tx.vout) {
+ for (const CTxOut& txout : tx.vout) {
if (!::IsStandard(txout.scriptPubKey, whichType, witnessEnabled)) {
reason = "scriptpubkey";
return false;
@@ -105,7 +128,7 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnes
else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) {
reason = "bare-multisig";
return false;
- } else if (txout.IsDust(dustRelayFee)) {
+ } else if (IsDust(txout, ::dustRelayFee)) {
reason = "dust";
return false;
}
@@ -120,6 +143,22 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnes
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
+ *
+ * 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 AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
{
if (tx.IsCoinBase())
@@ -127,7 +166,7 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
- const CTxOut& prev = mapInputs.GetOutputFor(tx.vin[i]);
+ const CTxOut& prev = mapInputs.AccessCoin(tx.vin[i].prevout).out;
std::vector<std::vector<unsigned char> > vSolutions;
txnouttype whichType;
@@ -166,7 +205,7 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
if (tx.vin[i].scriptWitness.IsNull())
continue;
- const CTxOut &prev = mapInputs.GetOutputFor(tx.vin[i]);
+ const CTxOut &prev = mapInputs.AccessCoin(tx.vin[i].prevout).out;
// get the scriptPubKey corresponding to this input:
CScript prevScript = prev.scriptPubKey;
diff --git a/src/policy/policy.h b/src/policy/policy.h
index 9b1323ac26..ef71dd73bc 100644
--- a/src/policy/policy.h
+++ b/src/policy/policy.h
@@ -7,19 +7,17 @@
#define BITCOIN_POLICY_POLICY_H
#include "consensus/consensus.h"
+#include "feerate.h"
#include "script/interpreter.h"
#include "script/standard.h"
#include <string>
class CCoinsViewCache;
+class CTxOut;
-/** Default for -blockmaxsize, which controls the maximum size of block the mining code will create **/
-static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 750000;
-/** Default for -blockprioritysize, maximum space for zero/low-fee transactions **/
-static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 0;
/** Default for -blockmaxweight, which controls the range of block weights the mining code will create **/
-static const unsigned int DEFAULT_BLOCK_MAX_WEIGHT = 3000000;
+static const unsigned int DEFAULT_BLOCK_MAX_WEIGHT = MAX_BLOCK_WEIGHT - 4000;
/** Default for -blockmintxfee, which sets the minimum feerate for a transaction in blocks created by mining code **/
static const unsigned int DEFAULT_BLOCK_MIN_TX_FEE = 1000;
/** The maximum weight for transactions we're willing to relay/mine */
@@ -40,12 +38,12 @@ static const unsigned int MAX_STANDARD_P2WSH_STACK_ITEMS = 100;
static const unsigned int MAX_STANDARD_P2WSH_STACK_ITEM_SIZE = 80;
/** The maximum size of a standard witnessScript */
static const unsigned int MAX_STANDARD_P2WSH_SCRIPT_SIZE = 3600;
-/** Min feerate for defining dust. Historically this has been the same as the
+/** Min feerate for defining dust. Historically this has been based on the
* minRelayTxFee, however changing the dust limit changes which transactions are
* standard and should be done with care and ideally rarely. It makes sense to
* only increase the dust limit after prior releases were already not creating
* outputs below the new threshold */
-static const unsigned int DUST_RELAY_TX_FEE = 1000;
+static const unsigned int DUST_RELAY_TX_FEE = 3000;
/**
* Standard script verification flags that standard transactions will comply
* with. However scripts violating these flags may still be present in valid
@@ -74,6 +72,10 @@ static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_
static const unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS = LOCKTIME_VERIFY_SEQUENCE |
LOCKTIME_MEDIAN_TIME_PAST;
+CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFee);
+
+bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFee);
+
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType, const bool witnessEnabled = false);
/**
* Check for standard transaction types
diff --git a/src/policy/rbf.cpp b/src/policy/rbf.cpp
index d9b47e71bb..755ef83c9a 100644
--- a/src/policy/rbf.cpp
+++ b/src/policy/rbf.cpp
@@ -6,7 +6,7 @@
bool SignalsOptInRBF(const CTransaction &tx)
{
- BOOST_FOREACH(const CTxIn &txin, tx.vin) {
+ for (const CTxIn &txin : tx.vin) {
if (txin.nSequence < std::numeric_limits<unsigned int>::max()-1) {
return true;
}
@@ -38,7 +38,7 @@ RBFTransactionState IsRBFOptIn(const CTransaction &tx, CTxMemPool &pool)
CTxMemPoolEntry entry = *pool.mapTx.find(tx.GetHash());
pool.CalculateMemPoolAncestors(entry, setAncestors, noLimit, noLimit, noLimit, noLimit, dummy, false);
- BOOST_FOREACH(CTxMemPool::txiter it, setAncestors) {
+ for (CTxMemPool::txiter it : setAncestors) {
if (SignalsOptInRBF(it->GetTx())) {
return RBF_TRANSACTIONSTATE_REPLACEABLE_BIP125;
}
diff --git a/src/policy/rbf.h b/src/policy/rbf.h
index 139aec5760..22c73f3319 100644
--- a/src/policy/rbf.h
+++ b/src/policy/rbf.h
@@ -7,6 +7,8 @@
#include "txmempool.h"
+static const uint32_t MAX_BIP125_RBF_SEQUENCE = 0xfffffffd;
+
enum RBFTransactionState {
RBF_TRANSACTIONSTATE_UNKNOWN,
RBF_TRANSACTIONSTATE_REPLACEABLE_BIP125,
diff --git a/src/pow.cpp b/src/pow.cpp
index e57fd866f8..7d87c6bbb7 100644
--- a/src/pow.cpp
+++ b/src/pow.cpp
@@ -12,12 +12,9 @@
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
{
+ assert(pindexLast != nullptr);
unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact();
- // Genesis block
- if (pindexLast == NULL)
- return nProofOfWorkLimit;
-
// Only change once per difficulty adjustment interval
if ((pindexLast->nHeight+1) % params.DifficultyAdjustmentInterval() != 0)
{
diff --git a/src/prevector.h b/src/prevector.h
index 6b2f578f5c..eb29b3ae7e 100644
--- a/src/prevector.h
+++ b/src/prevector.h
@@ -2,14 +2,16 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef _BITCOIN_PREVECTOR_H_
-#define _BITCOIN_PREVECTOR_H_
+#ifndef BITCOIN_PREVECTOR_H
+#define BITCOIN_PREVECTOR_H
+#include <assert.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <iterator>
+#include <type_traits>
#pragma pack(push, 1)
/** Implements a drop-in replacement for std::vector<T> which stores up to N
@@ -130,7 +132,7 @@ public:
typedef const T* pointer;
typedef const T& reference;
typedef std::bidirectional_iterator_tag iterator_category;
- const_reverse_iterator(T* ptr_) : ptr(ptr_) {}
+ const_reverse_iterator(const T* ptr_) : ptr(ptr_) {}
const_reverse_iterator(reverse_iterator x) : ptr(&(*x)) {}
const T& operator*() const { return *ptr; }
const T* operator->() const { return ptr; }
@@ -170,10 +172,15 @@ private:
}
} else {
if (!is_direct()) {
+ /* FIXME: Because malloc/realloc here won't call new_handler if allocation fails, assert
+ success. These should instead use an allocator or new/delete so that handlers
+ are called as necessary, but performance would be slightly degraded by doing so. */
_union.indirect = static_cast<char*>(realloc(_union.indirect, ((size_t)sizeof(T)) * new_capacity));
+ assert(_union.indirect);
_union.capacity = new_capacity;
} else {
char* new_indirect = static_cast<char*>(malloc(((size_t)sizeof(T)) * new_capacity));
+ assert(new_indirect);
T* src = direct_ptr(0);
T* dst = reinterpret_cast<T*>(new_indirect);
memcpy(dst, src, size() * sizeof(T));
@@ -213,7 +220,7 @@ public:
}
}
- prevector() : _size(0) {}
+ prevector() : _size(0), _union{{}} {}
explicit prevector(size_type n) : _size(0) {
resize(n);
@@ -380,12 +387,22 @@ public:
}
iterator erase(iterator first, iterator last) {
+ // Erase is not allowed to the change the object's capacity. That means
+ // that when starting with an indirectly allocated prevector with
+ // size and capacity > N, the result may be a still indirectly allocated
+ // prevector with size <= N and capacity > N. A shrink_to_fit() call is
+ // necessary to switch to the (more efficient) directly allocated
+ // representation (with capacity N and size <= N).
iterator p = first;
char* endp = (char*)&(*end());
- while (p != last) {
- (*p).~T();
- _size--;
- ++p;
+ if (!std::is_trivially_destructible<T>::value) {
+ while (p != last) {
+ (*p).~T();
+ _size--;
+ ++p;
+ }
+ } else {
+ _size -= last - p;
}
memmove(&(*first), &(*last), endp - ((char*)(&(*last))));
return first;
@@ -426,10 +443,12 @@ public:
}
~prevector() {
- clear();
+ if (!std::is_trivially_destructible<T>::value) {
+ clear();
+ }
if (!is_direct()) {
free(_union.indirect);
- _union.indirect = NULL;
+ _union.indirect = nullptr;
}
}
@@ -495,4 +514,4 @@ public:
};
#pragma pack(pop)
-#endif
+#endif // BITCOIN_PREVECTOR_H
diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp
index 9a979094cc..3774ac3e4b 100644
--- a/src/primitives/block.cpp
+++ b/src/primitives/block.cpp
@@ -25,18 +25,8 @@ std::string CBlock::ToString() const
hashMerkleRoot.ToString(),
nTime, nBits, nNonce,
vtx.size());
- for (unsigned int i = 0; i < vtx.size(); i++)
- {
- s << " " << vtx[i]->ToString() << "\n";
+ for (const auto& tx : vtx) {
+ s << " " << tx->ToString() << "\n";
}
return s.str();
}
-
-int64_t GetBlockWeight(const CBlock& block)
-{
- // This implements the weight = (stripped_size * 4) + witness_size formula,
- // using only serialization with and without witness data. As witness_size
- // is equal to total_size - stripped_size, this formula is identical to:
- // weight = (stripped_size * 3) + total_size.
- return ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION);
-}
diff --git a/src/primitives/block.h b/src/primitives/block.h
index 4c6eb20ad5..292df40896 100644
--- a/src/primitives/block.h
+++ b/src/primitives/block.h
@@ -129,10 +129,7 @@ struct CBlockLocator
CBlockLocator() {}
- CBlockLocator(const std::vector<uint256>& vHaveIn)
- {
- vHave = vHaveIn;
- }
+ explicit CBlockLocator(const std::vector<uint256>& vHaveIn) : vHave(vHaveIn) {}
ADD_SERIALIZE_METHODS;
@@ -155,7 +152,4 @@ struct CBlockLocator
}
};
-/** Compute the consensus-critical block weight (see BIP 141). */
-int64_t GetBlockWeight(const CBlock& tx);
-
#endif // BITCOIN_PRIMITIVES_BLOCK_H
diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp
index 790bc71d14..e0a106adb9 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -55,7 +55,7 @@ std::string CTxOut::ToString() const
}
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
-CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) {}
+CMutableTransaction::CMutableTransaction(const CTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime) {}
uint256 CMutableTransaction::GetHash() const
{
@@ -69,52 +69,28 @@ uint256 CTransaction::ComputeHash() const
uint256 CTransaction::GetWitnessHash() const
{
+ if (!HasWitness()) {
+ return GetHash();
+ }
return SerializeHash(*this, SER_GETHASH, 0);
}
/* For backward compatibility, the hash is initialized to 0. TODO: remove the need for this default constructor entirely. */
-CTransaction::CTransaction() : nVersion(CTransaction::CURRENT_VERSION), vin(), vout(), nLockTime(0), hash() {}
-CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime), hash(ComputeHash()) {}
-CTransaction::CTransaction(CMutableTransaction &&tx) : nVersion(tx.nVersion), vin(std::move(tx.vin)), vout(std::move(tx.vout)), nLockTime(tx.nLockTime), hash(ComputeHash()) {}
+CTransaction::CTransaction() : vin(), vout(), nVersion(CTransaction::CURRENT_VERSION), nLockTime(0), hash() {}
+CTransaction::CTransaction(const CMutableTransaction &tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash(ComputeHash()) {}
+CTransaction::CTransaction(CMutableTransaction &&tx) : vin(std::move(tx.vin)), vout(std::move(tx.vout)), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash(ComputeHash()) {}
CAmount CTransaction::GetValueOut() const
{
CAmount nValueOut = 0;
- for (std::vector<CTxOut>::const_iterator it(vout.begin()); it != vout.end(); ++it)
- {
- nValueOut += it->nValue;
- if (!MoneyRange(it->nValue) || !MoneyRange(nValueOut))
+ for (const auto& tx_out : vout) {
+ nValueOut += tx_out.nValue;
+ if (!MoneyRange(tx_out.nValue) || !MoneyRange(nValueOut))
throw std::runtime_error(std::string(__func__) + ": value out of range");
}
return nValueOut;
}
-double CTransaction::ComputePriority(double dPriorityInputs, unsigned int nTxSize) const
-{
- nTxSize = CalculateModifiedSize(nTxSize);
- if (nTxSize == 0) return 0.0;
-
- return dPriorityInputs / nTxSize;
-}
-
-unsigned int CTransaction::CalculateModifiedSize(unsigned int nTxSize) const
-{
- // In order to avoid disincentivizing cleaning up the UTXO set we don't count
- // the constant overhead for each txin and up to 110 bytes of scriptSig (which
- // is enough to cover a compressed pubkey p2sh redemption) for priority.
- // Providing any more cleanup incentive than making additional inputs free would
- // risk encouraging people to create junk outputs to redeem later.
- if (nTxSize == 0)
- nTxSize = (GetTransactionWeight(*this) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR;
- for (std::vector<CTxIn>::const_iterator it(vin.begin()); it != vin.end(); ++it)
- {
- unsigned int offset = 41U + std::min(110U, (unsigned int)it->scriptSig.size());
- if (nTxSize > offset)
- nTxSize -= offset;
- }
- return nTxSize;
-}
-
unsigned int CTransaction::GetTotalSize() const
{
return ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);
@@ -129,16 +105,11 @@ std::string CTransaction::ToString() const
vin.size(),
vout.size(),
nLockTime);
- for (unsigned int i = 0; i < vin.size(); i++)
- str += " " + vin[i].ToString() + "\n";
- for (unsigned int i = 0; i < vin.size(); i++)
- str += " " + vin[i].scriptWitness.ToString() + "\n";
- for (unsigned int i = 0; i < vout.size(); i++)
- str += " " + vout[i].ToString() + "\n";
+ for (const auto& tx_in : vin)
+ str += " " + tx_in.ToString() + "\n";
+ for (const auto& tx_in : vin)
+ str += " " + tx_in.scriptWitness.ToString() + "\n";
+ for (const auto& tx_out : vout)
+ str += " " + tx_out.ToString() + "\n";
return str;
}
-
-int64_t GetTransactionWeight(const CTransaction& tx)
-{
- return ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR -1) + ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
-}
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index af2986a41b..18d524e23d 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -6,6 +6,7 @@
#ifndef BITCOIN_PRIMITIVES_TRANSACTION_H
#define BITCOIN_PRIMITIVES_TRANSACTION_H
+#include <stdint.h>
#include "amount.h"
#include "script/script.h"
#include "serialize.h"
@@ -13,8 +14,6 @@
static const int SERIALIZE_TRANSACTION_NO_WITNESS = 0x40000000;
-static const int WITNESS_SCALE_FACTOR = 4;
-
/** An outpoint - a combination of a transaction hash and an index n into its vout */
class COutPoint
{
@@ -22,8 +21,8 @@ public:
uint256 hash;
uint32_t n;
- COutPoint() { SetNull(); }
- COutPoint(uint256 hashIn, uint32_t nIn) { hash = hashIn; n = nIn; }
+ COutPoint(): n((uint32_t) -1) { }
+ COutPoint(const uint256& hashIn, uint32_t nIn): hash(hashIn), n(nIn) { }
ADD_SERIALIZE_METHODS;
@@ -107,7 +106,7 @@ public:
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(prevout);
- READWRITE(*(CScriptBase*)(&scriptSig));
+ READWRITE(scriptSig);
READWRITE(nSequence);
}
@@ -147,7 +146,7 @@ public:
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(nValue);
- READWRITE(*(CScriptBase*)(&scriptPubKey));
+ READWRITE(scriptPubKey);
}
void SetNull()
@@ -161,43 +160,6 @@ public:
return (nValue == -1);
}
- CAmount GetDustThreshold(const CFeeRate &minRelayTxFee) const
- {
- // "Dust" is defined in terms of CTransaction::minRelayTxFee,
- // 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 spendable non-segwit txout is 34 bytes big, and will
- // need a CTxIn of at least 148 bytes to spend:
- // so dust is a spendable txout less than
- // 546*minRelayTxFee/1000 (in satoshis).
- // A typical spendable segwit txout is 31 bytes big, and will
- // need a CTxIn of at least 67 bytes to spend:
- // so dust is a spendable txout less than
- // 294*minRelayTxFee/1000 (in satoshis).
- if (scriptPubKey.IsUnspendable())
- return 0;
-
- size_t nSize = GetSerializeSize(*this, SER_DISK, 0);
- int witnessversion = 0;
- std::vector<unsigned char> witnessprogram;
-
- if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
- // sum the sizes of the parts of a transaction input
- // with 75% segwit discount applied to the script size.
- nSize += (32 + 4 + 1 + (107 / WITNESS_SCALE_FACTOR) + 4);
- } else {
- nSize += (32 + 4 + 1 + 107 + 4); // the 148 mentioned above
- }
-
- return 3 * minRelayTxFee.GetFee(nSize);
- }
-
- bool IsDust(const CFeeRate &minRelayTxFee) const
- {
- return (nValue < GetDustThreshold(minRelayTxFee));
- }
-
friend bool operator==(const CTxOut& a, const CTxOut& b)
{
return (a.nValue == b.nValue &&
@@ -316,9 +278,9 @@ public:
// actually immutable; deserialization and assignment are implemented,
// and bypass the constness. This is safe, as they update the entire
// structure, including the hash.
- const int32_t nVersion;
const std::vector<CTxIn> vin;
const std::vector<CTxOut> vout;
+ const int32_t nVersion;
const uint32_t nLockTime;
private:
@@ -361,12 +323,6 @@ public:
// GetValueIn() is a method on CCoinsViewCache, because
// inputs must be known to compute value in.
- // Compute priority, given priority of inputs and (optionally) tx size
- double ComputePriority(double dPriorityInputs, unsigned int nTxSize=0) const;
-
- // Compute modified tx size for priority calculation (optionally given tx size)
- unsigned int CalculateModifiedSize(unsigned int nTxSize=0) const;
-
/**
* Get the total transaction size in bytes, including witness data.
* "Total Size" defined in BIP141 and BIP144.
@@ -405,9 +361,9 @@ public:
/** A mutable version of CTransaction. */
struct CMutableTransaction
{
- int32_t nVersion;
std::vector<CTxIn> vin;
std::vector<CTxOut> vout;
+ int32_t nVersion;
uint32_t nLockTime;
CMutableTransaction();
@@ -454,7 +410,4 @@ typedef std::shared_ptr<const CTransaction> CTransactionRef;
static inline CTransactionRef MakeTransactionRef() { return std::make_shared<const CTransaction>(); }
template <typename Tx> static inline CTransactionRef MakeTransactionRef(Tx&& txIn) { return std::make_shared<const CTransaction>(std::forward<Tx>(txIn)); }
-/** Compute the weight of a transaction, as defined by BIP 141 */
-int64_t GetTransactionWeight(const CTransaction &tx);
-
#endif // BITCOIN_PRIMITIVES_TRANSACTION_H
diff --git a/src/protocol.cpp b/src/protocol.cpp
index 28d1d0eeb4..da87e40091 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -39,7 +39,7 @@ const char *SENDCMPCT="sendcmpct";
const char *CMPCTBLOCK="cmpctblock";
const char *GETBLOCKTXN="getblocktxn";
const char *BLOCKTXN="blocktxn";
-};
+} // namespace NetMsgType
/** All known message types. Keep this in the same order as the list of
* messages above and in protocol.h.
@@ -151,11 +151,7 @@ CInv::CInv()
hash.SetNull();
}
-CInv::CInv(int typeIn, const uint256& hashIn)
-{
- type = typeIn;
- hash = hashIn;
-}
+CInv::CInv(int typeIn, const uint256& hashIn) : type(typeIn), hash(hashIn) {}
bool operator<(const CInv& a, const CInv& b)
{
diff --git a/src/protocol.h b/src/protocol.h
index eba39ab1e5..67e01d9606 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -39,7 +39,7 @@ public:
};
typedef unsigned char MessageStartChars[MESSAGE_START_SIZE];
- CMessageHeader(const MessageStartChars& pchMessageStartIn);
+ explicit CMessageHeader(const MessageStartChars& pchMessageStartIn);
CMessageHeader(const MessageStartChars& pchMessageStartIn, const char* pszCommand, unsigned int nMessageSizeIn);
std::string GetCommand() const;
@@ -163,7 +163,7 @@ extern const char *PONG;
/**
* The notfound message is a reply to a getdata message which requested an
* object the receiving node does not have available for relay.
- * @ince protocol version 70001.
+ * @since protocol version 70001.
* @see https://bitcoin.org/en/developer-reference#notfound
*/
extern const char *NOTFOUND;
diff --git a/src/pubkey.cpp b/src/pubkey.cpp
index e57fa238cb..2da7be783f 100644
--- a/src/pubkey.cpp
+++ b/src/pubkey.cpp
@@ -10,8 +10,8 @@
namespace
{
/* Global secp256k1_context object used for verification. */
-secp256k1_context* secp256k1_context_verify = NULL;
-}
+secp256k1_context* secp256k1_context_verify = nullptr;
+} // namespace
/** This function is taken from the libsecp256k1 distribution and implements
* DER parsing for ECDSA signatures, while supporting an arbitrary subset of
@@ -172,10 +172,7 @@ bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchS
if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) {
return false;
}
- if (vchSig.size() == 0) {
- return false;
- }
- if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, &vchSig[0], vchSig.size())) {
+ if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, vchSig.data(), vchSig.size())) {
return false;
}
/* libsecp256k1's ECDSA verification requires lower-S signatures, which have
@@ -274,10 +271,10 @@ bool CExtPubKey::Derive(CExtPubKey &out, unsigned int _nChild) const {
/* static */ bool CPubKey::CheckLowS(const std::vector<unsigned char>& vchSig) {
secp256k1_ecdsa_signature sig;
- if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, &vchSig[0], vchSig.size())) {
+ if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, vchSig.data(), vchSig.size())) {
return false;
}
- return (!secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, NULL, &sig));
+ return (!secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, nullptr, &sig));
}
/* static */ int ECCVerifyHandle::refcount = 0;
@@ -285,9 +282,9 @@ bool CExtPubKey::Derive(CExtPubKey &out, unsigned int _nChild) const {
ECCVerifyHandle::ECCVerifyHandle()
{
if (refcount == 0) {
- assert(secp256k1_context_verify == NULL);
+ assert(secp256k1_context_verify == nullptr);
secp256k1_context_verify = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
- assert(secp256k1_context_verify != NULL);
+ assert(secp256k1_context_verify != nullptr);
}
refcount++;
}
@@ -296,8 +293,8 @@ ECCVerifyHandle::~ECCVerifyHandle()
{
refcount--;
if (refcount == 0) {
- assert(secp256k1_context_verify != NULL);
+ assert(secp256k1_context_verify != nullptr);
secp256k1_context_destroy(secp256k1_context_verify);
- secp256k1_context_verify = NULL;
+ secp256k1_context_verify = nullptr;
}
}
diff --git a/src/pubkey.h b/src/pubkey.h
index dbf0e23f20..65738d8fe2 100644
--- a/src/pubkey.h
+++ b/src/pubkey.h
@@ -30,7 +30,7 @@ class CKeyID : public uint160
{
public:
CKeyID() : uint160() {}
- CKeyID(const uint160& in) : uint160(in) {}
+ explicit CKeyID(const uint160& in) : uint160(in) {}
};
typedef uint256 ChainCode;
@@ -88,7 +88,7 @@ public:
}
//! Construct a public key from a byte vector.
- CPubKey(const std::vector<unsigned char>& _vch)
+ explicit CPubKey(const std::vector<unsigned char>& _vch)
{
Set(_vch.begin(), _vch.end());
}
diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp
index b1253a9f17..f295bd4689 100644
--- a/src/qt/addressbookpage.cpp
+++ b/src/qt/addressbookpage.cpp
@@ -254,7 +254,7 @@ void AddressBookPage::done(int retval)
// Figure out which address was selected, and return it
QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
- Q_FOREACH (const QModelIndex& index, indexes) {
+ for (const QModelIndex& index : indexes) {
QVariant address = table->model()->data(index);
returnValue = address.toString();
}
@@ -273,7 +273,7 @@ void AddressBookPage::on_exportButton_clicked()
// CSV is currently the only supported format
QString filename = GUIUtil::getSaveFileName(this,
tr("Export Address List"), QString(),
- tr("Comma separated file (*.csv)"), NULL);
+ tr("Comma separated file (*.csv)"), nullptr);
if (filename.isNull())
return;
diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h
index c22566d473..3c00fd0809 100644
--- a/src/qt/addressbookpage.h
+++ b/src/qt/addressbookpage.h
@@ -8,7 +8,6 @@
#include <QDialog>
class AddressTableModel;
-class OptionsModel;
class PlatformStyle;
namespace Ui {
@@ -20,7 +19,6 @@ class QItemSelection;
class QMenu;
class QModelIndex;
class QSortFilterProxyModel;
-class QTableView;
QT_END_NAMESPACE
/** Widget that shows a list of sending or receiving addresses.
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index 93120de1ea..0eb7ec4306 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -10,7 +10,6 @@
#include "base58.h"
#include "wallet/wallet.h"
-#include <boost/foreach.hpp>
#include <QFont>
#include <QDebug>
@@ -81,16 +80,16 @@ public:
cachedAddressTable.clear();
{
LOCK(wallet->cs_wallet);
- BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, wallet->mapAddressBook)
+ for (const std::pair<CTxDestination, CAddressBookData>& item : wallet->mapAddressBook)
{
- const CBitcoinAddress& address = item.first;
- bool fMine = IsMine(*wallet, address.Get());
+ const CTxDestination& address = item.first;
+ bool fMine = IsMine(*wallet, address);
AddressTableEntry::Type addressType = translateTransactionType(
QString::fromStdString(item.second.purpose), fMine);
const std::string& strName = item.second.name;
cachedAddressTable.append(AddressTableEntry(addressType,
QString::fromStdString(strName),
- QString::fromStdString(address.ToString())));
+ QString::fromStdString(EncodeDestination(address))));
}
}
// qLowerBound() and qUpperBound() require our cachedAddressTable list to be sorted in asc order
@@ -247,7 +246,7 @@ bool AddressTableModel::setData(const QModelIndex &index, const QVariant &value,
if(role == Qt::EditRole)
{
LOCK(wallet->cs_wallet); /* For SetAddressBook / DelAddressBook */
- CTxDestination curAddress = CBitcoinAddress(rec->address.toStdString()).Get();
+ CTxDestination curAddress = DecodeDestination(rec->address.toStdString());
if(index.column() == Label)
{
// Do nothing, if old label == new label
@@ -258,7 +257,7 @@ bool AddressTableModel::setData(const QModelIndex &index, const QVariant &value,
}
wallet->SetAddressBook(curAddress, value.toString().toStdString(), strPurpose);
} else if(index.column() == Address) {
- CTxDestination newAddress = CBitcoinAddress(value.toString().toStdString()).Get();
+ CTxDestination newAddress = DecodeDestination(value.toString().toStdString());
// Refuse to set invalid address, set error status and return false
if(boost::get<CNoDestination>(&newAddress))
{
@@ -359,7 +358,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
// Check for duplicate addresses
{
LOCK(wallet->cs_wallet);
- if(wallet->mapAddressBook.count(CBitcoinAddress(strAddress).Get()))
+ if(wallet->mapAddressBook.count(DecodeDestination(strAddress)))
{
editStatus = DUPLICATE_ADDRESS;
return QString();
@@ -385,7 +384,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
return QString();
}
}
- strAddress = CBitcoinAddress(newKey.GetID()).ToString();
+ strAddress = EncodeDestination(newKey.GetID());
}
else
{
@@ -395,7 +394,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
// Add entry
{
LOCK(wallet->cs_wallet);
- wallet->SetAddressBook(CBitcoinAddress(strAddress).Get(), strLabel,
+ wallet->SetAddressBook(DecodeDestination(strAddress), strLabel,
(type == Send ? "send" : "receive"));
}
return QString::fromStdString(strAddress);
@@ -413,7 +412,7 @@ bool AddressTableModel::removeRows(int row, int count, const QModelIndex &parent
}
{
LOCK(wallet->cs_wallet);
- wallet->DelAddressBook(CBitcoinAddress(rec->address.toStdString()).Get());
+ wallet->DelAddressBook(DecodeDestination(rec->address.toStdString()));
}
return true;
}
@@ -424,8 +423,8 @@ QString AddressTableModel::labelForAddress(const QString &address) const
{
{
LOCK(wallet->cs_wallet);
- CBitcoinAddress address_parsed(address.toStdString());
- std::map<CTxDestination, CAddressBookData>::iterator mi = wallet->mapAddressBook.find(address_parsed.Get());
+ CTxDestination destination = DecodeDestination(address.toStdString());
+ std::map<CTxDestination, CAddressBookData>::iterator mi = wallet->mapAddressBook.find(destination);
if (mi != wallet->mapAddressBook.end())
{
return QString::fromStdString(mi->second.name);
diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp
index 00a915dd8d..f8a99506c1 100644
--- a/src/qt/bantablemodel.cpp
+++ b/src/qt/bantablemodel.cpp
@@ -64,7 +64,7 @@ public:
}
if (sortColumn >= 0)
- // sort cachedBanlist (use stable sort to prevent rows jumping around unneceesarily)
+ // sort cachedBanlist (use stable sort to prevent rows jumping around unnecessarily)
qStableSort(cachedBanlist.begin(), cachedBanlist.end(), BannedNodeLessThan(sortColumn, sortOrder));
}
@@ -181,7 +181,5 @@ void BanTableModel::sort(int column, Qt::SortOrder order)
bool BanTableModel::shouldShow()
{
- if (priv->size() > 0)
- return true;
- return false;
+ return priv->size() > 0;
}
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 72f5f4aac9..3fd58a2f9a 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -10,6 +10,7 @@
#include "chainparams.h"
#include "clientmodel.h"
+#include "fs.h"
#include "guiconstants.h"
#include "guiutil.h"
#include "intro.h"
@@ -38,7 +39,6 @@
#include <stdint.h>
-#include <boost/filesystem/operations.hpp>
#include <boost/thread.hpp>
#include <QApplication>
@@ -106,7 +106,7 @@ static QString GetLangTerritory()
if(!lang_territory_qsettings.isEmpty())
lang_territory = lang_territory_qsettings;
// 3) -lang command line argument
- lang_territory = QString::fromStdString(GetArg("-lang", lang_territory.toStdString()));
+ lang_territory = QString::fromStdString(gArgs.GetArg("-lang", lang_territory.toStdString()));
return lang_territory;
}
@@ -152,15 +152,21 @@ static void initTranslations(QTranslator &qtTranslatorBase, QTranslator &qtTrans
#if QT_VERSION < 0x050000
void DebugMessageHandler(QtMsgType type, const char *msg)
{
- const char *category = (type == QtDebugMsg) ? "qt" : NULL;
- LogPrint(category, "GUI: %s\n", msg);
+ if (type == QtDebugMsg) {
+ LogPrint(BCLog::QT, "GUI: %s\n", msg);
+ } else {
+ LogPrintf("GUI: %s\n", msg);
+ }
}
#else
void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &msg)
{
Q_UNUSED(context);
- const char *category = (type == QtDebugMsg) ? "qt" : NULL;
- LogPrint(category, "GUI: %s\n", msg.toStdString());
+ if (type == QtDebugMsg) {
+ LogPrint(BCLog::QT, "GUI: %s\n", msg.toStdString());
+ } else {
+ LogPrintf("GUI: %s\n", msg.toStdString());
+ }
}
#endif
@@ -172,14 +178,18 @@ class BitcoinCore: public QObject
Q_OBJECT
public:
explicit BitcoinCore();
+ /** Basic initialization, before starting initialization/shutdown thread.
+ * Return true on success.
+ */
+ static bool baseInitialize();
public Q_SLOTS:
void initialize();
void shutdown();
Q_SIGNALS:
- void initializeResult(int retval);
- void shutdownResult(int retval);
+ void initializeResult(bool success);
+ void shutdownResult();
void runawayException(const QString &message);
private:
@@ -217,14 +227,14 @@ public:
void requestShutdown();
/// Get process return value
- int getReturnValue() { return returnValue; }
+ int getReturnValue() const { return returnValue; }
/// Get window identifier of QMainWindow (BitcoinGUI)
WId getMainWinId() const;
public Q_SLOTS:
- void initializeResult(int retval);
- void shutdownResult(int retval);
+ void initializeResult(bool success);
+ void shutdownResult();
/// Handle runaway exceptions. Shows a message box with the problem and quits the program.
void handleRunawayException(const QString &message);
@@ -264,32 +274,38 @@ void BitcoinCore::handleRunawayException(const std::exception *e)
Q_EMIT runawayException(QString::fromStdString(GetWarnings("gui")));
}
+bool BitcoinCore::baseInitialize()
+{
+ if (!AppInitBasicSetup())
+ {
+ return false;
+ }
+ if (!AppInitParameterInteraction())
+ {
+ return false;
+ }
+ if (!AppInitSanityChecks())
+ {
+ return false;
+ }
+ if (!AppInitLockDataDirectory())
+ {
+ return false;
+ }
+ return true;
+}
+
void BitcoinCore::initialize()
{
try
{
- qDebug() << __func__ << ": Running AppInit2 in thread";
- if (!AppInitBasicSetup())
- {
- Q_EMIT initializeResult(false);
- return;
- }
- if (!AppInitParameterInteraction())
- {
- Q_EMIT initializeResult(false);
- return;
- }
- if (!AppInitSanityChecks())
- {
- Q_EMIT initializeResult(false);
- return;
- }
- int rv = AppInitMain(threadGroup, scheduler);
+ qDebug() << __func__ << ": Running initialization in thread";
+ bool rv = AppInitMain(threadGroup, scheduler);
Q_EMIT initializeResult(rv);
} catch (const std::exception& e) {
handleRunawayException(&e);
} catch (...) {
- handleRunawayException(NULL);
+ handleRunawayException(nullptr);
}
}
@@ -302,11 +318,11 @@ void BitcoinCore::shutdown()
threadGroup.join_all();
Shutdown();
qDebug() << __func__ << ": Shutdown finished";
- Q_EMIT shutdownResult(1);
+ Q_EMIT shutdownResult();
} catch (const std::exception& e) {
handleRunawayException(&e);
} catch (...) {
- handleRunawayException(NULL);
+ handleRunawayException(nullptr);
}
}
@@ -329,7 +345,7 @@ BitcoinApplication::BitcoinApplication(int &argc, char **argv):
// This must be done inside the BitcoinApplication constructor, or after it, because
// PlatformStyle::instantiate requires a QApplication
std::string platformName;
- platformName = GetArg("-uiplatform", BitcoinGUI::DEFAULT_UIPLATFORM);
+ platformName = gArgs.GetArg("-uiplatform", BitcoinGUI::DEFAULT_UIPLATFORM);
platformStyle = PlatformStyle::instantiate(QString::fromStdString(platformName));
if (!platformStyle) // Fall back to "other" if specified name not found
platformStyle = PlatformStyle::instantiate("other");
@@ -367,7 +383,7 @@ void BitcoinApplication::createPaymentServer()
void BitcoinApplication::createOptionsModel(bool resetSettings)
{
- optionsModel = new OptionsModel(NULL, resetSettings);
+ optionsModel = new OptionsModel(nullptr, resetSettings);
}
void BitcoinApplication::createWindow(const NetworkStyle *networkStyle)
@@ -398,8 +414,8 @@ void BitcoinApplication::startThread()
executor->moveToThread(coreThread);
/* communication to and from thread */
- connect(executor, SIGNAL(initializeResult(int)), this, SLOT(initializeResult(int)));
- connect(executor, SIGNAL(shutdownResult(int)), this, SLOT(shutdownResult(int)));
+ connect(executor, SIGNAL(initializeResult(bool)), this, SLOT(initializeResult(bool)));
+ connect(executor, SIGNAL(shutdownResult()), this, SLOT(shutdownResult()));
connect(executor, SIGNAL(runawayException(QString)), this, SLOT(handleRunawayException(QString)));
connect(this, SIGNAL(requestedInitialize()), executor, SLOT(initialize()));
connect(this, SIGNAL(requestedShutdown()), executor, SLOT(shutdown()));
@@ -450,14 +466,14 @@ void BitcoinApplication::requestShutdown()
Q_EMIT requestedShutdown();
}
-void BitcoinApplication::initializeResult(int retval)
+void BitcoinApplication::initializeResult(bool success)
{
- qDebug() << __func__ << ": Initialization result: " << retval;
- // Set exit result: 0 if successful, 1 if failure
- returnValue = retval ? 0 : 1;
- if(retval)
+ qDebug() << __func__ << ": Initialization result: " << success;
+ // Set exit result.
+ returnValue = success ? EXIT_SUCCESS : EXIT_FAILURE;
+ if(success)
{
- // Log this only after AppInit2 finishes, as then logging setup is guaranteed complete
+ // Log this only after AppInitMain finishes, as then logging setup is guaranteed complete
qWarning() << "Platform customization:" << platformStyle->getName();
#ifdef ENABLE_WALLET
PaymentServer::LoadRootCAs();
@@ -468,9 +484,10 @@ void BitcoinApplication::initializeResult(int retval)
window->setClientModel(clientModel);
#ifdef ENABLE_WALLET
- if(pwalletMain)
+ // TODO: Expose secondary wallets
+ if (!vpwallets.empty())
{
- walletModel = new WalletModel(platformStyle, pwalletMain, optionsModel);
+ walletModel = new WalletModel(platformStyle, vpwallets[0], optionsModel);
window->addWallet(BitcoinGUI::DEFAULT_WALLET, walletModel);
window->setCurrentWallet(BitcoinGUI::DEFAULT_WALLET);
@@ -481,7 +498,7 @@ void BitcoinApplication::initializeResult(int retval)
#endif
// If -min option passed, start window minimized.
- if(GetBoolArg("-min", false))
+ if(gArgs.GetBoolArg("-min", false))
{
window->showMinimized();
}
@@ -507,9 +524,8 @@ void BitcoinApplication::initializeResult(int retval)
}
}
-void BitcoinApplication::shutdownResult(int retval)
+void BitcoinApplication::shutdownResult()
{
- qDebug() << __func__ << ": Shutdown result: " << retval;
quit(); // Exit main loop after shutdown finished
}
@@ -534,7 +550,7 @@ int main(int argc, char *argv[])
/// 1. Parse command-line options. These take precedence over anything else.
// Command-line options take precedence:
- ParseParameters(argc, argv);
+ gArgs.ParseParameters(argc, argv);
// Do not refer to data directory yet, this can be overridden by Intro::pickDataDirectory
@@ -572,6 +588,7 @@ int main(int argc, char *argv[])
// Need to pass name here as CAmount is a typedef (see http://qt-project.org/doc/qt-5/qmetatype.html#qRegisterMetaType)
// IMPORTANT if it is no longer a typedef use the normal variant above
qRegisterMetaType< CAmount >("CAmount");
+ qRegisterMetaType< std::function<void(void)> >("std::function<void(void)>");
/// 3. Application identification
// must be set before OptionsModel is initialized or translations are loaded,
@@ -589,9 +606,9 @@ int main(int argc, char *argv[])
// Show help message immediately after parsing command-line options (for "-lang") and setting locale,
// but before showing splash screen.
- if (IsArgSet("-?") || IsArgSet("-h") || IsArgSet("-help") || IsArgSet("-version"))
+ if (gArgs.IsArgSet("-?") || gArgs.IsArgSet("-h") || gArgs.IsArgSet("-help") || gArgs.IsArgSet("-version"))
{
- HelpMessageDialog help(NULL, IsArgSet("-version"));
+ HelpMessageDialog help(nullptr, gArgs.IsArgSet("-version"));
help.showOrPrint();
return EXIT_SUCCESS;
}
@@ -603,14 +620,14 @@ int main(int argc, char *argv[])
/// 6. Determine availability of data directory and parse bitcoin.conf
/// - Do not call GetDataDir(true) before this step finishes
- if (!boost::filesystem::is_directory(GetDataDir(false)))
+ if (!fs::is_directory(GetDataDir(false)))
{
QMessageBox::critical(0, QObject::tr(PACKAGE_NAME),
- QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(GetArg("-datadir", ""))));
+ QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(gArgs.GetArg("-datadir", ""))));
return EXIT_FAILURE;
}
try {
- ReadConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME));
+ gArgs.ReadConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME));
} catch (const std::exception& e) {
QMessageBox::critical(0, QObject::tr(PACKAGE_NAME),
QObject::tr("Error: Cannot parse configuration file: %1. Only use key=value syntax.").arg(e.what()));
@@ -674,31 +691,41 @@ int main(int argc, char *argv[])
// Allow parameter interaction before we create the options model
app.parameterSetup();
// Load GUI settings from QSettings
- app.createOptionsModel(IsArgSet("-resetguisettings"));
+ app.createOptionsModel(gArgs.IsArgSet("-resetguisettings"));
// Subscribe to global signals from core
uiInterface.InitMessage.connect(InitMessage);
- if (GetBoolArg("-splash", DEFAULT_SPLASHSCREEN) && !GetBoolArg("-min", false))
+ if (gArgs.GetBoolArg("-splash", DEFAULT_SPLASHSCREEN) && !gArgs.GetBoolArg("-min", false))
app.createSplashScreen(networkStyle.data());
+ int rv = EXIT_SUCCESS;
try
{
app.createWindow(networkStyle.data());
- app.requestInitialize();
+ // Perform base initialization before spinning up initialization/shutdown thread
+ // This is acceptable because this function only contains steps that are quick to execute,
+ // so the GUI thread won't be held up.
+ if (BitcoinCore::baseInitialize()) {
+ app.requestInitialize();
#if defined(Q_OS_WIN) && QT_VERSION >= 0x050000
- WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely...").arg(QObject::tr(PACKAGE_NAME)), (HWND)app.getMainWinId());
+ WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely...").arg(QObject::tr(PACKAGE_NAME)), (HWND)app.getMainWinId());
#endif
- app.exec();
- app.requestShutdown();
- app.exec();
+ app.exec();
+ app.requestShutdown();
+ app.exec();
+ rv = app.getReturnValue();
+ } else {
+ // A dialog with detailed error will have been shown by InitError()
+ rv = EXIT_FAILURE;
+ }
} catch (const std::exception& e) {
PrintExceptionContinue(&e, "Runaway exception");
app.handleRunawayException(QString::fromStdString(GetWarnings("gui")));
} catch (...) {
- PrintExceptionContinue(NULL, "Runaway exception");
+ PrintExceptionContinue(nullptr, "Runaway exception");
app.handleRunawayException(QString::fromStdString(GetWarnings("gui")));
}
- return app.getReturnValue();
+ return rv;
}
#endif // BITCOIN_QT_TEST
diff --git a/src/qt/bitcoinaddressvalidator.cpp b/src/qt/bitcoinaddressvalidator.cpp
index d712705c43..362a71f04d 100644
--- a/src/qt/bitcoinaddressvalidator.cpp
+++ b/src/qt/bitcoinaddressvalidator.cpp
@@ -67,7 +67,7 @@ QValidator::State BitcoinAddressEntryValidator::validate(QString &input, int &po
if (((ch >= '0' && ch<='9') ||
(ch >= 'a' && ch<='z') ||
(ch >= 'A' && ch<='Z')) &&
- ch != 'l' && ch != 'I' && ch != '0' && ch != 'O')
+ ch != 'I' && ch != 'O') // Characters invalid in both Base58 and Bech32
{
// Alphanumeric and not a 'forbidden' character
}
@@ -89,9 +89,9 @@ QValidator::State BitcoinAddressCheckValidator::validate(QString &input, int &po
{
Q_UNUSED(pos);
// Validate the passed Bitcoin address
- CBitcoinAddress addr(input.toStdString());
- if (addr.IsValid())
+ if (IsValidDestinationString(input.toStdString())) {
return QValidator::Acceptable;
+ }
return QValidator::Invalid;
}
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index a3cb376bcf..dc55141900 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -31,6 +31,7 @@
#include "macdockiconhandler.h"
#endif
+#include "chainparams.h"
#include "init.h"
#include "ui_interface.h"
#include "util.h"
@@ -122,7 +123,11 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *_platformStyle, const NetworkStyle *
spinnerFrame(0),
platformStyle(_platformStyle)
{
- GUIUtil::restoreWindowGeometry("nWindow", QSize(850, 550), this);
+ QSettings settings;
+ if (!restoreGeometry(settings.value("MainWindowGeometry").toByteArray())) {
+ // Restore failed (perhaps missing setting), center the window
+ move(QApplication::desktop()->availableGeometry().center() - frameGeometry().center());
+ }
QString windowTitle = tr(PACKAGE_NAME) + " - ";
#ifdef ENABLE_WALLET
@@ -260,7 +265,8 @@ BitcoinGUI::~BitcoinGUI()
// Unsubscribe from notifications from core
unsubscribeFromCoreSignals();
- GUIUtil::saveWindowGeometry("nWindow", this);
+ QSettings settings;
+ settings.setValue("MainWindowGeometry", saveGeometry());
if(trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu)
trayIcon->hide();
#ifdef Q_OS_MAC
@@ -453,6 +459,7 @@ void BitcoinGUI::createToolBars()
if(walletFrame)
{
QToolBar *toolbar = addToolBar(tr("Tabs toolbar"));
+ toolbar->setContextMenuPolicy(Qt::PreventContextMenu);
toolbar->setMovable(false);
toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
toolbar->addAction(overviewAction);
@@ -477,7 +484,8 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel)
connect(_clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
connect(_clientModel, SIGNAL(networkActiveChanged(bool)), this, SLOT(setNetworkActive(bool)));
- setNumBlocks(_clientModel->getNumBlocks(), _clientModel->getLastBlockDate(), _clientModel->getVerificationProgress(NULL), false);
+ modalOverlay->setKnownBestHeight(_clientModel->getHeaderTipHeight(), QDateTime::fromTime_t(_clientModel->getHeaderTipTime()));
+ setNumBlocks(_clientModel->getNumBlocks(), _clientModel->getLastBlockDate(), _clientModel->getVerificationProgress(nullptr), false);
connect(_clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,double,bool)));
// Receive and report messages from client model
@@ -504,8 +512,6 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel)
// initialize the disable state of the tray icon with the current value in the model.
setTrayIconVisible(optionsModel->getHideTrayIcon());
}
-
- modalOverlay->setKnownBestHeight(clientModel->getHeaderTipHeight(), QDateTime::fromTime_t(clientModel->getHeaderTipTime()));
} else {
// Disable possibility to show main window via action
toggleHideAction->setEnabled(false);
@@ -517,7 +523,10 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel)
// Propagate cleared model to child objects
rpcConsole->setClientModel(nullptr);
#ifdef ENABLE_WALLET
- walletFrame->setClientModel(nullptr);
+ if (walletFrame)
+ {
+ walletFrame->setClientModel(nullptr);
+ }
#endif // ENABLE_WALLET
unitDisplayControl->setOptionsModel(nullptr);
}
@@ -748,6 +757,15 @@ void BitcoinGUI::setNetworkActive(bool networkActive)
updateNetworkState();
}
+void BitcoinGUI::updateHeadersSyncProgressLabel()
+{
+ int64_t headersTipTime = clientModel->getHeaderTipTime();
+ int headersTipHeight = clientModel->getHeaderTipHeight();
+ int estHeadersLeft = (GetTime() - headersTipTime) / Params().GetConsensus().nPowTargetSpacing;
+ if (estHeadersLeft > HEADER_HEIGHT_DELTA_SYNC)
+ progressBarLabel->setText(tr("Syncing Headers (%1%)...").arg(QString::number(100.0 / (headersTipHeight+estHeadersLeft)*headersTipHeight, 'f', 1)));
+}
+
void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool header)
{
if (modalOverlay)
@@ -760,7 +778,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer
if (!clientModel)
return;
- // Prevent orphan statusbar messages (e.g. hover Quit in main menu, wait until chain-sync starts -> garbelled text)
+ // Prevent orphan statusbar messages (e.g. hover Quit in main menu, wait until chain-sync starts -> garbled text)
statusBar()->clearMessage();
// Acquire current block source
@@ -768,9 +786,11 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer
switch (blockSource) {
case BLOCK_SOURCE_NETWORK:
if (header) {
+ updateHeadersSyncProgressLabel();
return;
}
progressBarLabel->setText(tr("Synchronizing with network..."));
+ updateHeadersSyncProgressLabel();
break;
case BLOCK_SOURCE_DISK:
if (header) {
@@ -786,8 +806,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer
if (header) {
return;
}
- // Case: not Importing, not Reindexing and no network connection
- progressBarLabel->setText(tr("No block source available..."));
+ progressBarLabel->setText(tr("Connecting to peers..."));
break;
}
@@ -909,7 +928,7 @@ void BitcoinGUI::message(const QString &title, const QString &message, unsigned
showNormalIfMinimized();
QMessageBox mBox((QMessageBox::Icon)nMBoxIcon, strTitle, message, buttons, this);
int r = mBox.exec();
- if (ret != NULL)
+ if (ret != nullptr)
*ret = r == QMessageBox::Ok;
}
else
@@ -993,7 +1012,7 @@ void BitcoinGUI::dropEvent(QDropEvent *event)
{
if(event->mimeData()->hasUrls())
{
- Q_FOREACH(const QUrl &uri, event->mimeData()->urls())
+ for (const QUrl &uri : event->mimeData()->urls())
{
Q_EMIT receivedURI(uri.toString());
}
@@ -1189,7 +1208,7 @@ UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(const PlatformStyle *pl
QList<BitcoinUnits::Unit> units = BitcoinUnits::availableUnits();
int max_width = 0;
const QFontMetrics fm(font());
- Q_FOREACH (const BitcoinUnits::Unit unit, units)
+ for (const BitcoinUnits::Unit unit : units)
{
max_width = qMax(max_width, fm.width(BitcoinUnits::name(unit)));
}
@@ -1208,7 +1227,7 @@ void UnitDisplayStatusBarControl::mousePressEvent(QMouseEvent *event)
void UnitDisplayStatusBarControl::createContextMenu()
{
menu = new QMenu(this);
- Q_FOREACH(BitcoinUnits::Unit u, BitcoinUnits::availableUnits())
+ for (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 c8b6ce5474..aa45ea1f0a 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -31,8 +31,6 @@ class WalletModel;
class HelpMessageDialog;
class ModalOverlay;
-class CWallet;
-
QT_BEGIN_NAMESPACE
class QAction;
class QProgressBar;
@@ -149,6 +147,8 @@ private:
/** Update UI with latest network info from model. */
void updateNetworkState();
+ void updateHeadersSyncProgressLabel();
+
Q_SIGNALS:
/** Signal raised when a URI was entered or dragged to the GUI */
void receivedURI(const QString &uri);
@@ -168,7 +168,7 @@ public Q_SLOTS:
@see CClientUIInterface::MessageBoxFlags
@param[in] ret pointer to a bool that will be modified to whether Ok was clicked (modal only)
*/
- void message(const QString &title, const QString &message, unsigned int style, bool *ret = NULL);
+ void message(const QString &title, const QString &message, unsigned int style, bool *ret = nullptr);
#ifdef ENABLE_WALLET
/** Set the encryption status as shown in the UI.
diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp
index 64bc7dac03..9f798ccf62 100644
--- a/src/qt/bitcoinstrings.cpp
+++ b/src/qt/bitcoinstrings.cpp
@@ -21,9 +21,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"A fee rate (in %s/kB) that will be used when fee estimation has insufficient "
"data (default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Accept connections from outside (default: 1 if no -proxy or -connect/-"
-"noconnect)"),
-QT_TRANSLATE_NOOP("bitcoin-core", ""
"Accept relayed transactions received from whitelisted peers even when not "
"relaying transactions (default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -37,14 +34,16 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Bind to given address and whitelist peers connecting to it. Use [host]:port "
"notation for IPv6"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Bind to given address to listen for JSON-RPC connections. Use [host]:port "
-"notation for IPv6. This option can be specified multiple times (default: "
-"bind to all interfaces)"),
+"Bind to given address to listen for JSON-RPC connections. This option is "
+"ignored unless -rpcallowip is also passed. Port is optional and overrides -"
+"rpcport. Use [host]:port notation for IPv6. This option can be specified "
+"multiple times (default: 127.0.0.1 and ::1 i.e., localhost, or if -"
+"rpcallowip has been specified, 0.0.0.0 and :: i.e., all addresses)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Cannot obtain a lock on data directory %s. %s is probably already running."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Connect only to the specified node(s); -noconnect or -connect=0 alone to "
-"disable automatic connections"),
+"Connect only to the specified node(s); -connect=0 disables automatic "
+"connections"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Create new files with system default permissions, instead of umask 077 (only "
"effective with disabled wallet functionality)"),
@@ -62,13 +61,20 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Equivalent bytes per sigop in transactions for relay and mining (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Error loading %s: You can't enable HD on a already existing non-HD wallet"),
+"Error loading %s: You can't enable HD on an already existing non-HD wallet"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Error loading wallet %s. -wallet parameter must only specify a filename (not "
+"a path)."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Error reading %s! All keys read correctly, but transaction data or address "
"book entries might be missing or incorrect."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Error: Listening for incoming connections failed (listen returned error %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Exclude debugging information for a category. Can be used in conjunction "
+"with -debug=1 to output debug logs for all categories except one or more "
+"specified categories."),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Execute command when a relevant alert is received or we see a really long "
"fork (%s in cmd is replaced by message)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -78,6 +84,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Execute command when the best block changes (%s in cmd is replaced by block "
"hash)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Extra transactions to keep in memory for compact block reconstructions "
+"(default: %u)"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Fees (in %s/kB) smaller than this are considered zero fee for relaying, "
"mining and transaction creation (default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -95,6 +104,10 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"If paytxfee is not set, include enough fee so transactions begin "
"confirmation on average within n blocks (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"If this block is in the chain assume that it and its ancestors are valid and "
+"potentially skip their script verification (0 to verify all, default: %s, "
+"testnet: %s)"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay "
"fee of %s to prevent stuck transactions)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -127,7 +140,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"reindex (download the whole blockchain again in case of pruned node)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Query for peer addresses via DNS lookup, if low on addresses (default: 1 "
-"unless -connect/-noconnect)"),
+"unless -connect used)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Randomize credentials for every proxy connection. This enables Tor stream "
"isolation (default: %u)"),
@@ -147,8 +160,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Set lowest fee rate (in %s/kB) for transactions to be included in block "
"creation. (default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Set maximum size of high-priority/low-fee transactions in bytes (default: %d)"),
-QT_TRANSLATE_NOOP("bitcoin-core", ""
"Set the number of script verification threads (%u to %d, 0 = auto, <0 = "
"leave that many cores free, default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -162,11 +173,19 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"rebuild the block database if you are sure that your computer's date and "
"time are correct"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"The fee rate (in %s/kB) that indicates your tolerance for discarding change "
+"by adding it to the fee (default: %s). Note: An output is discarded if it is "
+"dust at this rate, but we will always discard up to the dust relay fee and a "
+"discard fee above that is limited by the fee estimate for the longest target"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"The transaction amount is too small to send after the fee has been deducted"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"This is a pre-release test build - use at your own risk - do not use for "
"mining or merchant applications"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"This is the transaction fee you may discard if change is smaller than dust "
+"at this level"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"This is the transaction fee you may pay when fee estimates are not available."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"This product includes software developed by the OpenSSL Project for use in "
@@ -179,6 +198,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = "
"no limit (default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Unable to replay blocks. You will need to rebuild the database using -"
+"reindex-chainstate."),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Unable to rewind the database to a pre-fork state. You will need to "
"redownload the blockchain"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -218,6 +240,8 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Warning: We do not appear to fully agree with our peers! You may need to "
"upgrade, or other nodes may need to upgrade."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Whether to save the mempool on shutdown and load on restart (default: %u)"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR "
"notated network (e.g. 1.2.3.0/24). Can be specified multiple times."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -228,13 +252,16 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"mode. This will redownload the entire blockchain"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"You need to rebuild the database using -reindex-chainstate to change -txindex"),
+QT_TRANSLATE_NOOP("bitcoin-core", "%d of last 100 blocks have unexpected version"),
QT_TRANSLATE_NOOP("bitcoin-core", "%s corrupt, salvage failed"),
QT_TRANSLATE_NOOP("bitcoin-core", "%s is set very high!"),
QT_TRANSLATE_NOOP("bitcoin-core", "(default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "(default: %u)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "(press q to shutdown and continue later)"),
QT_TRANSLATE_NOOP("bitcoin-core", "-maxmempool must be at least %d MB"),
QT_TRANSLATE_NOOP("bitcoin-core", "<category> can be:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Accept command line and JSON-RPC commands"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Accept connections from outside (default: 1 if no -proxy or -connect)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Accept public REST requests (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Add a node to connect to and attempt to keep the connection open"),
QT_TRANSLATE_NOOP("bitcoin-core", "Allow DNS lookups for -addnode, -seednode and -connect"),
@@ -267,10 +294,14 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Error initializing wallet database environmen
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s: Wallet corrupted"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s: Wallet requires newer version of %s"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s: You can't disable HD on a already existing HD wallet"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s: You can't disable HD on an already existing HD wallet"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading block database"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet %s. -wallet filename must be a regular file."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet %s. Duplicate -wallet filename specified."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet %s. Invalid characters in -wallet filename."),
QT_TRANSLATE_NOOP("bitcoin-core", "Error opening block database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error reading from database, shutting down."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error upgrading chainstate database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: A fatal internal error occurred, see debug.log for details"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Disk space is low!"),
@@ -284,9 +315,10 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Incorrect or no genesis block found. Wrong da
QT_TRANSLATE_NOOP("bitcoin-core", "Information"),
QT_TRANSLATE_NOOP("bitcoin-core", "Initialization sanity check failed. %s is shutting down."),
QT_TRANSLATE_NOOP("bitcoin-core", "Insufficient funds"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -onion address: '%s'"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -proxy address: '%s'"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -onion address or hostname: '%s'"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -proxy address or hostname: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -%s=<amount>: '%s'"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -discardfee=<amount>: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -fallbackfee=<amount>: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid netmask specified in -whitelist: '%s'"),
@@ -295,7 +327,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Keep the transaction memory pool below <n> me
QT_TRANSLATE_NOOP("bitcoin-core", "Keypool ran out, please call keypoolrefill first"),
QT_TRANSLATE_NOOP("bitcoin-core", "Listen for JSON-RPC connections on <port> (default: %u or testnet: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Listen for connections on <port> (default: %u or testnet: %u)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Loading addresses..."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Loading P2P addresses..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading banlist..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading block index..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading wallet..."),
@@ -322,12 +354,12 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Rebuild chain state from the currently indexe
QT_TRANSLATE_NOOP("bitcoin-core", "Reducing -maxconnections from %d to %d, because of system limitations."),
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", "Replaying blocks..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Rescan the block chain for missing wallet transactions on startup"),
QT_TRANSLATE_NOOP("bitcoin-core", "Rescanning..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Rewinding blocks..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Run in the background as a daemon and accept commands"),
QT_TRANSLATE_NOOP("bitcoin-core", "Send trace/debug info to console instead of debug.log file"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Send transactions as zero-fee transactions if possible (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Send transactions with full-RBF opt-in enabled (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Set database cache size in megabytes (%d to %d, default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Set key pool size to <n> (default: %u)"),
@@ -356,6 +388,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Tor control port password (default: empty)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Tor control port to use if onion listening enabled (default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction amount too small"),
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction amounts must not be negative"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Transaction fee and change calculation failed"),
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction has too long of a mempool chain"),
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction must have at least one recipient"),
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction too large for fee policy"),
@@ -367,13 +400,15 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Unknown network specified in -onlynet: '%s'")
QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported argument -benchmark ignored, use -debug=bench."),
QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported argument -debugnet ignored, use -debug=net."),
QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported argument -tor found, use -onion."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported logging category %s=%s."),
QT_TRANSLATE_NOOP("bitcoin-core", "Upgrade wallet to latest format on startup"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Upgrading UTXO database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Use UPnP to map the listening port (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Use the test chain"),
QT_TRANSLATE_NOOP("bitcoin-core", "User Agent comment (%s) contains unsafe characters."),
QT_TRANSLATE_NOOP("bitcoin-core", "Username for JSON-RPC connections"),
QT_TRANSLATE_NOOP("bitcoin-core", "Verifying blocks..."),
-QT_TRANSLATE_NOOP("bitcoin-core", "Verifying wallet..."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Verifying wallet(s)..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Wallet %s resides outside data directory %s"),
QT_TRANSLATE_NOOP("bitcoin-core", "Wallet debugging/testing options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Wallet needed to be rewritten: restart %s to complete"),
diff --git a/src/qt/callback.h b/src/qt/callback.h
new file mode 100644
index 0000000000..da6b0c4c2e
--- /dev/null
+++ b/src/qt/callback.h
@@ -0,0 +1,30 @@
+#ifndef BITCOIN_QT_CALLBACK_H
+#define BITCOIN_QT_CALLBACK_H
+
+#include <QObject>
+
+class Callback : public QObject
+{
+ Q_OBJECT
+public Q_SLOTS:
+ virtual void call() = 0;
+};
+
+template <typename F>
+class FunctionCallback : public Callback
+{
+ F f;
+
+public:
+ explicit FunctionCallback(F f_) : f(std::move(f_)) {}
+ ~FunctionCallback() override {}
+ void call() override { f(this); }
+};
+
+template <typename F>
+FunctionCallback<F>* makeCallback(F f)
+{
+ return new FunctionCallback<F>(std::move(f));
+}
+
+#endif // BITCOIN_QT_CALLBACK_H
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index bb10e49422..52ce11cefd 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -9,6 +9,7 @@
#include "guiutil.h"
#include "peertablemodel.h"
+#include "chain.h"
#include "chainparams.h"
#include "checkpoints.h"
#include "clientversion.h"
@@ -17,6 +18,7 @@
#include "txmempool.h"
#include "ui_interface.h"
#include "util.h"
+#include "warnings.h"
#include <stdint.h>
@@ -25,7 +27,6 @@
class CBlockIndex;
-static const int64_t nClientStartupTime = GetTime();
static int64_t nLastHeaderTipUpdateNotification = 0;
static int64_t nLastBlockTipUpdateNotification = 0;
@@ -36,6 +37,8 @@ ClientModel::ClientModel(OptionsModel *_optionsModel, QObject *parent) :
banTableModel(0),
pollTimer(0)
{
+ cachedBestHeaderHeight = -1;
+ cachedBestHeaderTime = -1;
peerTableModel = new PeerTableModel(this);
banTableModel = new BanTableModel(this);
pollTimer = new QTimer(this);
@@ -74,18 +77,28 @@ int ClientModel::getNumBlocks() const
int ClientModel::getHeaderTipHeight() const
{
- LOCK(cs_main);
- if (!pindexBestHeader)
- return 0;
- return pindexBestHeader->nHeight;
+ if (cachedBestHeaderHeight == -1) {
+ // make sure we initially populate the cache via a cs_main lock
+ // otherwise we need to wait for a tip update
+ LOCK(cs_main);
+ if (pindexBestHeader) {
+ cachedBestHeaderHeight = pindexBestHeader->nHeight;
+ cachedBestHeaderTime = pindexBestHeader->GetBlockTime();
+ }
+ }
+ return cachedBestHeaderHeight;
}
int64_t ClientModel::getHeaderTipTime() const
{
- LOCK(cs_main);
- if (!pindexBestHeader)
- return 0;
- return pindexBestHeader->GetBlockTime();
+ if (cachedBestHeaderTime == -1) {
+ LOCK(cs_main);
+ if (pindexBestHeader) {
+ cachedBestHeaderHeight = pindexBestHeader->nHeight;
+ cachedBestHeaderTime = pindexBestHeader->GetBlockTime();
+ }
+ }
+ return cachedBestHeaderTime;
}
quint64 ClientModel::getTotalBytesRecv() const
@@ -225,7 +238,7 @@ bool ClientModel::isReleaseVersion() const
QString ClientModel::formatClientStartupTime() const
{
- return QDateTime::fromTime_t(nClientStartupTime).toString();
+ return QDateTime::fromTime_t(GetStartupTime()).toString();
}
QString ClientModel::dataDir() const
@@ -283,9 +296,14 @@ static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CB
int64_t& nLastUpdateNotification = fHeader ? nLastHeaderTipUpdateNotification : nLastBlockTipUpdateNotification;
+ if (fHeader) {
+ // cache best headers time and height to reduce future cs_main locks
+ clientmodel->cachedBestHeaderHeight = pIndex->nHeight;
+ clientmodel->cachedBestHeaderTime = pIndex->GetBlockTime();
+ }
// if we are in-sync, update the UI regardless of last update time
if (!initialSync || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) {
- //pass a async signal to the UI thread
+ //pass an async signal to the UI thread
QMetaObject::invokeMethod(clientmodel, "numBlocksChanged", Qt::QueuedConnection,
Q_ARG(int, pIndex->nHeight),
Q_ARG(QDateTime, QDateTime::fromTime_t(pIndex->GetBlockTime())),
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index c01c1a84cf..6447cae1bb 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -8,13 +8,12 @@
#include <QObject>
#include <QDateTime>
-class AddressTableModel;
+#include <atomic>
+
class BanTableModel;
class OptionsModel;
class PeerTableModel;
-class TransactionTableModel;
-class CWallet;
class CBlockIndex;
QT_BEGIN_NAMESPACE
@@ -66,7 +65,7 @@ public:
//! Return true if core is doing initial block download
bool inInitialBlockDownload() const;
- //! Return true if core is importing blocks
+ //! Returns enum BlockSource of the current importing/syncing state
enum BlockSource getBlockSource() const;
//! Return true if network activity in core is enabled
bool getNetworkActive() const;
@@ -81,6 +80,10 @@ public:
QString formatClientStartupTime() const;
QString dataDir() const;
+ // caches for the best header
+ mutable std::atomic<int> cachedBestHeaderHeight;
+ mutable std::atomic<int64_t> cachedBestHeaderTime;
+
private:
OptionsModel *optionsModel;
PeerTableModel *peerTableModel;
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index f8aba70d92..3ca43eae22 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -15,12 +15,12 @@
#include "wallet/coincontrol.h"
#include "init.h"
+#include "policy/fees.h"
#include "policy/policy.h"
#include "validation.h" // For mempool
+#include "wallet/fees.h"
#include "wallet/wallet.h"
-#include <boost/assign/list_of.hpp> // for 'map_list_of()'
-
#include <QApplication>
#include <QCheckBox>
#include <QCursor>
@@ -425,7 +425,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
CAmount nPayAmount = 0;
bool fDust = false;
CMutableTransaction txDummy;
- Q_FOREACH(const CAmount &amount, CoinControlDialog::payAmounts)
+ for (const CAmount &amount : CoinControlDialog::payAmounts)
{
nPayAmount += amount;
@@ -433,8 +433,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
{
CTxOut txout(amount, (CScript)std::vector<unsigned char>(24, 0));
txDummy.vout.push_back(txout);
- if (txout.IsDust(dustRelayFee))
- fDust = true;
+ fDust |= IsDust(txout, ::dustRelayFee);
}
}
@@ -444,11 +443,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
CAmount nChange = 0;
unsigned int nBytes = 0;
unsigned int nBytesInputs = 0;
- double dPriority = 0;
- double dPriorityInputs = 0;
unsigned int nQuantity = 0;
- int nQuantityUncompressed = 0;
- bool fAllowFree = false;
bool fWitness = false;
std::vector<COutPoint> vCoinControl;
@@ -456,7 +451,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
coinControl->ListSelected(vCoinControl);
model->getOutputs(vCoinControl, vOutputs);
- BOOST_FOREACH(const COutput& out, vOutputs) {
+ for (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();
@@ -473,9 +468,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
// Amount
nAmount += out.tx->tx->vout[out.i].nValue;
- // Priority
- dPriorityInputs += (double)out.tx->tx->vout[out.i].nValue * (out.nDepth+1);
-
// Bytes
CTxDestination address;
int witnessversion = 0;
@@ -492,8 +484,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
if (keyid && model->getPubKey(*keyid, pubkey))
{
nBytesInputs += (pubkey.IsCompressed() ? 148 : 180);
- if (!pubkey.IsCompressed())
- nQuantityUncompressed++;
}
else
nBytesInputs += 148; // in all error cases, simply assume 148 here
@@ -510,7 +500,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
{
// there is some fudging in these numbers related to the actual virtual transaction size calculation that will keep this estimate from being exact.
// usually, the result will be an overestimate within a couple of satoshis so that the confirmation dialog ends up displaying a slightly smaller fee.
- // also, the witness stack size value value is a variable sized integer. usually, the number of stack items will be well under the single byte var int limit.
+ // also, the witness stack size value is a variable sized integer. usually, the number of stack items will be well under the single byte var int limit.
nBytes += 2; // account for the serialized marker and flag bytes
nBytes += nQuantity; // account for the witness byte that holds the number of stack items for each input.
}
@@ -521,20 +511,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
nBytes -= 34;
// Fee
- nPayFee = CWallet::GetMinimumFee(nBytes, nTxConfirmTarget, mempool);
- if (nPayFee > 0 && coinControl->nMinimumTotalFee > nPayFee)
- nPayFee = coinControl->nMinimumTotalFee;
-
-
- // Allow free? (require at least hard-coded threshold and default to that if no estimate)
- double mempoolEstimatePriority = mempool.estimateSmartPriority(nTxConfirmTarget);
- dPriority = dPriorityInputs / (nBytes - nBytesInputs + (nQuantityUncompressed * 29)); // 29 = 180 - 151 (uncompressed public keys are over the limit. max 151 bytes of the input are ignored for priority)
- double dPriorityNeeded = std::max(mempoolEstimatePriority, AllowFreeThreshold());
- fAllowFree = (dPriority >= dPriorityNeeded);
-
- if (fSendFreeTransactions)
- if (fAllowFree && nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE)
- nPayFee = 0;
+ nPayFee = GetMinimumFee(nBytes, *coinControl, ::mempool, ::feeEstimator, nullptr /* FeeCalculation */);
if (nPayAmount > 0)
{
@@ -546,15 +523,12 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
if (nChange > 0 && nChange < MIN_CHANGE)
{
CTxOut txout(nChange, (CScript)std::vector<unsigned char>(24, 0));
- if (txout.IsDust(dustRelayFee))
+ if (IsDust(txout, ::dustRelayFee))
{
- if (CoinControlDialog::fSubtractFeeFromAmount) // dust-change will be raised until no dust
- nChange = txout.GetDustThreshold(dustRelayFee);
- else
- {
- nPayFee += nChange;
- nChange = 0;
- }
+ nPayFee += nChange;
+ nChange = 0;
+ if (CoinControlDialog::fSubtractFeeFromAmount)
+ nBytes -= 34; // we didn't detect lack of change above
}
}
@@ -563,9 +537,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
}
// after fee
- nAfterFee = nAmount - nPayFee;
- if (nAfterFee < 0)
- nAfterFee = 0;
+ nAfterFee = std::max<CAmount>(nAmount - nPayFee, 0);
}
// actually update labels
@@ -595,7 +567,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
l5->setText(((nBytes > 0) ? ASYMP_UTF8 : "") + QString::number(nBytes)); // Bytes
l7->setText(fDust ? tr("yes") : tr("no")); // Dust
l8->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nChange)); // Change
- if (nPayFee > 0 && (coinControl->nMinimumTotalFee < nPayFee))
+ if (nPayFee > 0)
{
l3->setText(ASYMP_UTF8 + l3->text());
l4->setText(ASYMP_UTF8 + l4->text());
@@ -610,12 +582,8 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
QString toolTipDust = tr("This label turns red if any recipient receives an amount smaller than the current dust threshold.");
// how many satoshis the estimated fee can vary per byte we guess wrong
- double dFeeVary;
- if (payTxFee.GetFeePerK() > 0)
- dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), payTxFee.GetFeePerK()) / 1000;
- else {
- dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), mempool.estimateSmartFee(nTxConfirmTarget).GetFeePerK()) / 1000;
- }
+ double dFeeVary = (double)nPayFee / nBytes;
+
QString toolTip4 = tr("Can vary +/- %1 satoshi(s) per input.").arg(dFeeVary);
l3->setToolTip(toolTip4);
@@ -652,7 +620,7 @@ void CoinControlDialog::updateView()
std::map<QString, std::vector<COutput> > mapCoins;
model->listCoins(mapCoins);
- BOOST_FOREACH(const PAIRTYPE(QString, std::vector<COutput>)& coins, mapCoins) {
+ for (const std::pair<QString, std::vector<COutput>>& coins : mapCoins) {
CCoinControlWidgetItem *itemWalletAddress = new CCoinControlWidgetItem();
itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
QString sWalletAddress = coins.first;
@@ -677,7 +645,7 @@ void CoinControlDialog::updateView()
CAmount nSum = 0;
int nChildren = 0;
- BOOST_FOREACH(const COutput& out, coins.second) {
+ for (const COutput& out : coins.second) {
nSum += out.tx->tx->vout[out.i].nValue;
nChildren++;
@@ -692,7 +660,7 @@ void CoinControlDialog::updateView()
QString sAddress = "";
if(ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, outputAddress))
{
- sAddress = QString::fromStdString(CBitcoinAddress(outputAddress).ToString());
+ sAddress = QString::fromStdString(EncodeDestination(outputAddress));
// if listMode or change => show bitcoin address. In tree mode, address is not shown again for direct wallet address outputs
if (!treeMode || (!(sAddress == sWalletAddress)))
diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h
index 0b8162f858..4949c91771 100644
--- a/src/qt/coincontroldialog.h
+++ b/src/qt/coincontroldialog.h
@@ -20,7 +20,6 @@ class PlatformStyle;
class WalletModel;
class CCoinControl;
-class CTxMemPool;
namespace Ui {
class CoinControlDialog;
@@ -31,9 +30,9 @@ namespace Ui {
class CCoinControlWidgetItem : public QTreeWidgetItem
{
public:
- CCoinControlWidgetItem(QTreeWidget *parent, int type = Type) : QTreeWidgetItem(parent, type) {}
- CCoinControlWidgetItem(int type = Type) : QTreeWidgetItem(type) {}
- CCoinControlWidgetItem(QTreeWidgetItem *parent, int type = Type) : QTreeWidgetItem(parent, type) {}
+ explicit CCoinControlWidgetItem(QTreeWidget *parent, int type = Type) : QTreeWidgetItem(parent, type) {}
+ explicit CCoinControlWidgetItem(int type = Type) : QTreeWidgetItem(type) {}
+ explicit CCoinControlWidgetItem(QTreeWidgetItem *parent, int type = Type) : QTreeWidgetItem(parent, type) {}
bool operator<(const QTreeWidgetItem &other) const;
};
diff --git a/src/qt/coincontroltreewidget.cpp b/src/qt/coincontroltreewidget.cpp
index f86bc0851f..88510b6168 100644
--- a/src/qt/coincontroltreewidget.cpp
+++ b/src/qt/coincontroltreewidget.cpp
@@ -16,9 +16,10 @@ void CoinControlTreeWidget::keyPressEvent(QKeyEvent *event)
if (event->key() == Qt::Key_Space) // press spacebar -> select checkbox
{
event->ignore();
- int COLUMN_CHECKBOX = 0;
- if(this->currentItem())
+ if (this->currentItem()) {
+ int COLUMN_CHECKBOX = 0;
this->currentItem()->setCheckState(COLUMN_CHECKBOX, ((this->currentItem()->checkState(COLUMN_CHECKBOX) == Qt::Checked) ? Qt::Unchecked : Qt::Checked));
+ }
}
else if (event->key() == Qt::Key_Escape) // press esc -> close dialog
{
diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui
index 8be4a955b3..093e644bdc 100644
--- a/src/qt/forms/debugwindow.ui
+++ b/src/qt/forms/debugwindow.ui
@@ -645,7 +645,7 @@
<item>
<widget class="QPushButton" name="btnClearTrafficGraph">
<property name="text">
- <string>&amp;Clear</string>
+ <string>&amp;Reset</string>
</property>
<property name="autoDefault">
<bool>false</bool>
diff --git a/src/qt/forms/intro.ui b/src/qt/forms/intro.ui
index e4ff3da1ab..cfdd8482e3 100644
--- a/src/qt/forms/intro.ui
+++ b/src/qt/forms/intro.ui
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>674</width>
- <height>363</height>
+ <height>415</height>
</rect>
</property>
<property name="windowTitle">
@@ -55,9 +55,6 @@
</item>
<item>
<widget class="QLabel" name="sizeWarningLabel">
- <property name="text">
- <string>%1 will download and store a copy of the Bitcoin block chain. At least %2GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory.</string>
- </property>
<property name="wordWrap">
<bool>true</bool>
</property>
@@ -204,6 +201,36 @@
</layout>
</item>
<item>
+ <widget class="QLabel" name="lblExplanation1">
+ <property name="text">
+ <string>When you click OK, %1 will begin to download and process the full %4 block chain (%2GB) starting with the earliest transactions in %3 when %4 initially launched.</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="lblExplanation2">
+ <property name="text">
+ <string>This initial synchronisation is very demanding, and may expose hardware problems with your computer that had previously gone unnoticed. Each time you run %1, it will continue downloading where it left off.</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="lblExplanation3">
+ <property name="text">
+ <string>If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui
index 0b29201872..e31bfee05e 100644
--- a/src/qt/forms/optionsdialog.ui
+++ b/src/qt/forms/optionsdialog.ui
@@ -199,10 +199,10 @@
<item>
<widget class="QCheckBox" name="allowIncoming">
<property name="toolTip">
- <string>Accept connections from outside</string>
+ <string>Accept connections from outside.</string>
</property>
<property name="text">
- <string>Allow incoming connections</string>
+ <string>Allow incomin&amp;g connections</string>
</property>
</widget>
</item>
@@ -315,7 +315,7 @@
<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>
+ <string>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</string>
</property>
<property name="text">
<string/>
@@ -338,7 +338,7 @@
<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>
+ <string>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</string>
</property>
<property name="text">
<string/>
@@ -361,7 +361,7 @@
<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>
+ <string>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</string>
</property>
<property name="text">
<string/>
@@ -399,7 +399,7 @@
<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>
+ <string>Use separate SOCKS&amp;5 proxy to reach peers via Tor hidden services:</string>
</property>
</widget>
</item>
@@ -507,10 +507,10 @@
<item>
<widget class="QCheckBox" name="hideTrayIcon">
<property name="toolTip">
- <string>&amp;Hide the icon from the system tray.</string>
+ <string>Hide the icon from the system tray.</string>
</property>
<property name="text">
- <string>Hide tray icon</string>
+ <string>&amp;Hide tray icon</string>
</property>
</widget>
</item>
@@ -610,7 +610,7 @@
<string>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 |.</string>
</property>
<property name="text">
- <string>Third party transaction URLs</string>
+ <string>&amp;Third party transaction URLs</string>
</property>
<property name="buddy">
<cstring>thirdPartyTxUrls</cstring>
@@ -692,17 +692,34 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayout_Buttons">
<item>
- <widget class="QPushButton" name="resetButton">
- <property name="toolTip">
- <string>Reset all client options to default.</string>
- </property>
- <property name="text">
- <string>&amp;Reset Options</string>
- </property>
- <property name="autoDefault">
- <bool>false</bool>
- </property>
- </widget>
+ <layout class="QVBoxLayout" name="verticalLayout_Buttons">
+ <item>
+ <widget class="QPushButton" name="openBitcoinConfButton">
+ <property name="toolTip">
+ <string>Open the %1 configuration file from the working directory.</string>
+ </property>
+ <property name="text">
+ <string>Open Configuration File</string>
+ </property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="resetButton">
+ <property name="toolTip">
+ <string>Reset all client options to default.</string>
+ </property>
+ <property name="text">
+ <string>&amp;Reset Options</string>
+ </property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
</item>
<item>
<spacer name="horizontalSpacer_1">
@@ -756,27 +773,48 @@
</spacer>
</item>
<item>
- <widget class="QPushButton" name="okButton">
- <property name="text">
- <string>&amp;OK</string>
- </property>
- <property name="autoDefault">
- <bool>false</bool>
- </property>
- <property name="default">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="cancelButton">
- <property name="text">
- <string>&amp;Cancel</string>
- </property>
- <property name="autoDefault">
- <bool>false</bool>
- </property>
- </widget>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QPushButton" name="okButton">
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="cancelButton">
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
</item>
</layout>
</item>
diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui
index ca8ecffafe..a0e48334c1 100644
--- a/src/qt/forms/sendcoinsdialog.ui
+++ b/src/qt/forms/sendcoinsdialog.ui
@@ -760,10 +760,32 @@
</layout>
</item>
<item>
+ <widget class="QLabel" name="fallbackFeeWarningLabel">
+ <property name="toolTip">
+ <string>Using the fallbackfee can result in sending a transaction that will take several hours or days (or never) to confirm. Consider choosing your fee manually or wait until you have validated the complete chain.</string>
+ </property>
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Warning: Fee estimation is currently not possible.</string>
+ </property>
+ <property name="wordWrap">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
+ <property name="sizeType">
+ <enum>QSizePolicy::MinimumExpanding</enum>
+ </property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
@@ -824,32 +846,13 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayoutFee13">
<item>
- <widget class="QRadioButton" name="radioCustomPerKilobyte">
+ <widget class="QLabel" name="labelCustomPerKilobyte">
<property name="toolTip">
<string>If the custom fee is set to 1000 satoshis and the transaction is only 250 bytes, then &quot;per kilobyte&quot; only pays 250 satoshis in fee, while &quot;total at least&quot; pays 1000 satoshis. For transactions bigger than a kilobyte both pay by kilobyte.</string>
</property>
<property name="text">
<string>per kilobyte</string>
</property>
- <property name="checked">
- <bool>true</bool>
- </property>
- <attribute name="buttonGroup">
- <string notr="true">groupCustomFee</string>
- </attribute>
- </widget>
- </item>
- <item>
- <widget class="QRadioButton" name="radioCustomAtLeast">
- <property name="toolTip">
- <string>If the custom fee is set to 1000 satoshis and the transaction is only 250 bytes, then &quot;per kilobyte&quot; only pays 250 satoshis in fee, while &quot;total at least&quot; pays 1000 satoshis. For transactions bigger than a kilobyte both pay by kilobyte.</string>
- </property>
- <property name="text">
- <string>total at least</string>
- </property>
- <attribute name="buttonGroup">
- <string notr="true">groupCustomFee</string>
- </attribute>
</widget>
</item>
<item>
@@ -1059,64 +1062,15 @@
<number>30</number>
</property>
<item>
- <widget class="QSlider" name="sliderSmartFee">
- <property name="minimum">
+ <layout class="QHBoxLayout" name="horizontalLayoutConfTarget">
+ <property name="bottomMargin">
<number>0</number>
</property>
- <property name="maximum">
- <number>23</number>
- </property>
- <property name="pageStep">
- <number>1</number>
- </property>
- <property name="value">
- <number>0</number>
- </property>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="invertedAppearance">
- <bool>false</bool>
- </property>
- <property name="invertedControls">
- <bool>false</bool>
- </property>
- <property name="tickPosition">
- <enum>QSlider::NoTicks</enum>
- </property>
- </widget>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayoutFee10">
- <item>
- <widget class="QLabel" name="labelSmartFeeNormal">
- <property name="text">
- <string>normal</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_7">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
<item>
- <widget class="QLabel" name="confirmationTargetLabel">
- <property name="text">
- <string notr="true">(count)</string>
- </property>
- </widget>
+ <widget class="QComboBox" name="confTargetSelector"/>
</item>
<item>
- <spacer name="horizontalSpacer_3">
+ <spacer name="horizontalSpacerConfTarget">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@@ -1128,13 +1082,6 @@
</property>
</spacer>
</item>
- <item>
- <widget class="QLabel" name="labelSmartFeeFast">
- <property name="text">
- <string>fast</string>
- </property>
- </widget>
- </item>
</layout>
</item>
</layout>
@@ -1158,6 +1105,16 @@
</item>
</layout>
</item>
+ <item>
+ <widget class="QCheckBox" name="optInRBF">
+ <property name="text">
+ <string>Request Replace-By-Fee</string>
+ </property>
+ <property name="toolTip">
+ <string>Indicates that the sender may wish to replace this transaction with a new one paying higher fees (prior to being confirmed).</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</item>
@@ -1168,8 +1125,8 @@
</property>
<property name="sizeHint" stdset="0">
<size>
- <width>800</width>
- <height>1</height>
+ <width>40</width>
+ <height>5</height>
</size>
</property>
</spacer>
@@ -1203,7 +1160,7 @@
<bool>false</bool>
</property>
<property name="default">
- <bool>true</bool>
+ <bool>false</bool>
</property>
</widget>
</item>
@@ -1322,6 +1279,5 @@
<connections/>
<buttongroups>
<buttongroup name="groupFee"/>
- <buttongroup name="groupCustomFee"/>
</buttongroups>
</ui>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index ea80a1f549..d520d7d4be 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -9,6 +9,7 @@
#include "qvalidatedlineedit.h"
#include "walletmodel.h"
+#include "fs.h"
#include "primitives/transaction.h"
#include "init.h"
#include "policy/policy.h"
@@ -35,11 +36,6 @@
#include "shlwapi.h"
#endif
-#include <boost/filesystem.hpp>
-#include <boost/filesystem/fstream.hpp>
-#if BOOST_FILESYSTEM_VERSION >= 3
-#include <boost/filesystem/detail/utf8_codecvt_facet.hpp>
-#endif
#include <boost/scoped_array.hpp>
#include <QAbstractItemView>
@@ -67,9 +63,7 @@
#include <QFontDatabase>
#endif
-#if BOOST_FILESYSTEM_VERSION >= 3
-static boost::filesystem::detail::utf8_codecvt_facet utf8;
-#endif
+static fs::detail::utf8_codecvt_facet utf8;
#if defined(Q_OS_MAC)
extern double NSAppKitVersionNumber;
@@ -118,8 +112,9 @@ static std::string DummyAddress(const CChainParams &params)
sourcedata.insert(sourcedata.end(), dummydata, dummydata + sizeof(dummydata));
for(int i=0; i<256; ++i) { // Try every trailing byte
std::string s = EncodeBase58(sourcedata.data(), sourcedata.data() + sourcedata.size());
- if (!CBitcoinAddress(s).IsValid())
+ if (!IsValidDestinationString(s)) {
return s;
+ }
sourcedata[sourcedata.size()-1] += 1;
}
return "";
@@ -254,10 +249,10 @@ QString formatBitcoinURI(const SendCoinsRecipient &info)
bool isDust(const QString& address, const CAmount& amount)
{
- CTxDestination dest = CBitcoinAddress(address.toStdString()).Get();
+ CTxDestination dest = DecodeDestination(address.toStdString());
CScript script = GetScriptForDestination(dest);
CTxOut txOut(amount, script);
- return txOut.IsDust(dustRelayFee);
+ return IsDust(txOut, ::dustRelayFee);
}
QString HtmlEscape(const QString& str, bool fMultiLine)
@@ -414,13 +409,29 @@ bool isObscured(QWidget *w)
void openDebugLogfile()
{
- boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
+ fs::path pathDebug = GetDataDir() / "debug.log";
/* Open debug.log with the associated application */
- if (boost::filesystem::exists(pathDebug))
+ if (fs::exists(pathDebug))
QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathDebug)));
}
+bool openBitcoinConf()
+{
+ boost::filesystem::path pathConfig = GetConfigFile(BITCOIN_CONF_FILENAME);
+
+ /* Create the file */
+ boost::filesystem::ofstream configFile(pathConfig, std::ios_base::app);
+
+ if (!configFile.good())
+ return false;
+
+ configFile.close();
+
+ /* Open bitcoin.conf with the associated application */
+ return QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathConfig)));
+}
+
void SubstituteFonts(const QString& language)
{
#if defined(Q_OS_MAC)
@@ -447,7 +458,7 @@ void SubstituteFonts(const QString& language)
/* 10.10 or later system */
if (language == "zh_CN" || language == "zh_TW" || language == "zh_HK") // traditional or simplified Chinese
QFont::insertSubstitution(".Helvetica Neue DeskInterface", "Heiti SC");
- else if (language == "ja") // Japanesee
+ else if (language == "ja") // Japanese
QFont::insertSubstitution(".Helvetica Neue DeskInterface", "Songti SC");
else
QFont::insertSubstitution(".Helvetica Neue DeskInterface", "Lucida Grande");
@@ -536,7 +547,7 @@ int TableViewLastColumnResizingFixer::getAvailableWidthForColumn(int column)
return nResult;
}
-// Make sure we don't make the columns wider than the tables viewport width.
+// Make sure we don't make the columns wider than the table's viewport width.
void TableViewLastColumnResizingFixer::adjustTableColumnsWidth()
{
disconnectViewHeadersSignals();
@@ -570,7 +581,7 @@ void TableViewLastColumnResizingFixer::on_sectionResized(int logicalIndex, int o
}
}
-// When the tabless geometry is ready, we manually perform the stretch of the "Message" column,
+// When the table's geometry is ready, we manually perform the stretch of the "Message" column,
// as the "Stretch" resize mode does not allow for interactive resizing.
void TableViewLastColumnResizingFixer::on_geometriesChanged()
{
@@ -601,7 +612,7 @@ TableViewLastColumnResizingFixer::TableViewLastColumnResizingFixer(QTableView* t
}
#ifdef WIN32
-boost::filesystem::path static StartupShortcutPath()
+fs::path static StartupShortcutPath()
{
std::string chain = ChainNameFromCommandLine();
if (chain == CBaseChainParams::MAIN)
@@ -614,21 +625,21 @@ boost::filesystem::path static StartupShortcutPath()
bool GetStartOnSystemStartup()
{
// check for Bitcoin*.lnk
- return boost::filesystem::exists(StartupShortcutPath());
+ return fs::exists(StartupShortcutPath());
}
bool SetStartOnSystemStartup(bool fAutoStart)
{
// If the shortcut exists already, remove it for updating
- boost::filesystem::remove(StartupShortcutPath());
+ fs::remove(StartupShortcutPath());
if (fAutoStart)
{
- CoInitialize(NULL);
+ CoInitialize(nullptr);
// Get a pointer to the IShellLink interface.
- IShellLink* psl = NULL;
- HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL,
+ IShellLink* psl = nullptr;
+ HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr,
CLSCTX_INPROC_SERVER, IID_IShellLink,
reinterpret_cast<void**>(&psl));
@@ -636,12 +647,12 @@ bool SetStartOnSystemStartup(bool fAutoStart)
{
// Get the current executable path
TCHAR pszExePath[MAX_PATH];
- GetModuleFileName(NULL, pszExePath, sizeof(pszExePath));
+ GetModuleFileName(nullptr, pszExePath, sizeof(pszExePath));
// Start client minimized
QString strArgs = "-min";
// Set -testnet /-regtest options
- strArgs += QString::fromStdString(strprintf(" -testnet=%d -regtest=%d", GetBoolArg("-testnet", false), GetBoolArg("-regtest", false)));
+ strArgs += QString::fromStdString(strprintf(" -testnet=%d -regtest=%d", gArgs.GetBoolArg("-testnet", false), gArgs.GetBoolArg("-regtest", false)));
#ifdef UNICODE
boost::scoped_array<TCHAR> args(new TCHAR[strArgs.length() + 1]);
@@ -664,7 +675,7 @@ bool SetStartOnSystemStartup(bool fAutoStart)
// Query IShellLink for the IPersistFile interface for
// saving the shortcut in persistent storage.
- IPersistFile* ppf = NULL;
+ IPersistFile* ppf = nullptr;
hres = psl->QueryInterface(IID_IPersistFile, reinterpret_cast<void**>(&ppf));
if (SUCCEEDED(hres))
{
@@ -690,10 +701,8 @@ bool SetStartOnSystemStartup(bool fAutoStart)
// Follow the Desktop Application Autostart Spec:
// http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
-boost::filesystem::path static GetAutostartDir()
+fs::path static GetAutostartDir()
{
- namespace fs = boost::filesystem;
-
char* pszConfigHome = getenv("XDG_CONFIG_HOME");
if (pszConfigHome) return fs::path(pszConfigHome) / "autostart";
char* pszHome = getenv("HOME");
@@ -701,7 +710,7 @@ boost::filesystem::path static GetAutostartDir()
return fs::path();
}
-boost::filesystem::path static GetAutostartFilePath()
+fs::path static GetAutostartFilePath()
{
std::string chain = ChainNameFromCommandLine();
if (chain == CBaseChainParams::MAIN)
@@ -711,7 +720,7 @@ boost::filesystem::path static GetAutostartFilePath()
bool GetStartOnSystemStartup()
{
- boost::filesystem::ifstream optionFile(GetAutostartFilePath());
+ fs::ifstream optionFile(GetAutostartFilePath());
if (!optionFile.good())
return false;
// Scan through file for "Hidden=true":
@@ -731,17 +740,18 @@ bool GetStartOnSystemStartup()
bool SetStartOnSystemStartup(bool fAutoStart)
{
if (!fAutoStart)
- boost::filesystem::remove(GetAutostartFilePath());
+ fs::remove(GetAutostartFilePath());
else
{
char pszExePath[MAX_PATH+1];
- memset(pszExePath, 0, sizeof(pszExePath));
- if (readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1) == -1)
+ ssize_t r = readlink("/proc/self/exe", pszExePath, sizeof(pszExePath) - 1);
+ if (r == -1)
return false;
+ pszExePath[r] = '\0';
- boost::filesystem::create_directories(GetAutostartDir());
+ fs::create_directories(GetAutostartDir());
- boost::filesystem::ofstream optionFile(GetAutostartFilePath(), std::ios_base::out|std::ios_base::trunc);
+ fs::ofstream optionFile(GetAutostartFilePath(), std::ios_base::out|std::ios_base::trunc);
if (!optionFile.good())
return false;
std::string chain = ChainNameFromCommandLine();
@@ -752,7 +762,7 @@ bool SetStartOnSystemStartup(bool fAutoStart)
optionFile << "Name=Bitcoin\n";
else
optionFile << strprintf("Name=Bitcoin (%s)\n", chain);
- optionFile << "Exec=" << pszExePath << strprintf(" -min -testnet=%d -regtest=%d\n", GetBoolArg("-testnet", false), GetBoolArg("-regtest", false));
+ optionFile << "Exec=" << pszExePath << strprintf(" -min -testnet=%d -regtest=%d\n", gArgs.GetBoolArg("-testnet", false), gArgs.GetBoolArg("-regtest", false));
optionFile << "Terminal=false\n";
optionFile << "Hidden=false\n";
optionFile.close();
@@ -762,6 +772,8 @@ bool SetStartOnSystemStartup(bool fAutoStart)
#elif defined(Q_OS_MAC)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
// based on: https://github.com/Mozketo/LaunchAtLoginController/blob/master/LaunchAtLoginController.m
#include <CoreFoundation/CoreFoundation.h>
@@ -770,60 +782,80 @@ bool SetStartOnSystemStartup(bool fAutoStart)
LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl);
LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl)
{
+ CFArrayRef listSnapshot = LSSharedFileListCopySnapshot(list, nullptr);
+ if (listSnapshot == nullptr) {
+ return nullptr;
+ }
+
// loop through the list of startup items and try to find the bitcoin app
- CFArrayRef listSnapshot = LSSharedFileListCopySnapshot(list, NULL);
for(int i = 0; i < CFArrayGetCount(listSnapshot); i++) {
LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(listSnapshot, i);
UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes;
- CFURLRef currentItemURL = NULL;
+ CFURLRef currentItemURL = nullptr;
#if defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED >= 10100
- if(&LSSharedFileListItemCopyResolvedURL)
- currentItemURL = LSSharedFileListItemCopyResolvedURL(item, resolutionFlags, NULL);
+ if(&LSSharedFileListItemCopyResolvedURL)
+ currentItemURL = LSSharedFileListItemCopyResolvedURL(item, resolutionFlags, nullptr);
#if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && MAC_OS_X_VERSION_MIN_REQUIRED < 10100
- else
- LSSharedFileListItemResolve(item, resolutionFlags, &currentItemURL, NULL);
+ else
+ LSSharedFileListItemResolve(item, resolutionFlags, &currentItemURL, nullptr);
#endif
#else
- LSSharedFileListItemResolve(item, resolutionFlags, &currentItemURL, NULL);
+ LSSharedFileListItemResolve(item, resolutionFlags, &currentItemURL, nullptr);
#endif
- if(currentItemURL && CFEqual(currentItemURL, findUrl)) {
- // found
- CFRelease(currentItemURL);
- return item;
- }
if(currentItemURL) {
+ if (CFEqual(currentItemURL, findUrl)) {
+ // found
+ CFRelease(listSnapshot);
+ CFRelease(currentItemURL);
+ return item;
+ }
CFRelease(currentItemURL);
}
}
- return NULL;
+
+ CFRelease(listSnapshot);
+ return nullptr;
}
bool GetStartOnSystemStartup()
{
CFURLRef bitcoinAppUrl = CFBundleCopyBundleURL(CFBundleGetMainBundle());
- LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
+ if (bitcoinAppUrl == nullptr) {
+ return false;
+ }
+
+ LSSharedFileListRef loginItems = LSSharedFileListCreate(nullptr, kLSSharedFileListSessionLoginItems, nullptr);
LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, bitcoinAppUrl);
+
+ CFRelease(bitcoinAppUrl);
return !!foundItem; // return boolified object
}
bool SetStartOnSystemStartup(bool fAutoStart)
{
CFURLRef bitcoinAppUrl = CFBundleCopyBundleURL(CFBundleGetMainBundle());
- LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
+ if (bitcoinAppUrl == nullptr) {
+ return false;
+ }
+
+ LSSharedFileListRef loginItems = LSSharedFileListCreate(nullptr, kLSSharedFileListSessionLoginItems, nullptr);
LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, bitcoinAppUrl);
if(fAutoStart && !foundItem) {
// add bitcoin app to startup item list
- LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemBeforeFirst, NULL, NULL, bitcoinAppUrl, NULL, NULL);
+ LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemBeforeFirst, nullptr, nullptr, bitcoinAppUrl, nullptr, nullptr);
}
else if(!fAutoStart && foundItem) {
// remove item
LSSharedFileListItemRemove(loginItems, foundItem);
}
+
+ CFRelease(bitcoinAppUrl);
return true;
}
+#pragma GCC diagnostic pop
#else
bool GetStartOnSystemStartup() { return false; }
@@ -831,57 +863,21 @@ bool SetStartOnSystemStartup(bool fAutoStart) { return false; }
#endif
-void saveWindowGeometry(const QString& strSetting, QWidget *parent)
-{
- QSettings settings;
- settings.setValue(strSetting + "Pos", parent->pos());
- settings.setValue(strSetting + "Size", parent->size());
-}
-
-void restoreWindowGeometry(const QString& strSetting, const QSize& defaultSize, QWidget *parent)
-{
- QSettings settings;
- QPoint pos = settings.value(strSetting + "Pos").toPoint();
- QSize size = settings.value(strSetting + "Size", defaultSize).toSize();
-
- if (!pos.x() && !pos.y()) {
- QRect screen = QApplication::desktop()->screenGeometry();
- pos.setX((screen.width() - size.width()) / 2);
- pos.setY((screen.height() - size.height()) / 2);
- }
-
- parent->resize(size);
- parent->move(pos);
-}
-
void setClipboard(const QString& str)
{
QApplication::clipboard()->setText(str, QClipboard::Clipboard);
QApplication::clipboard()->setText(str, QClipboard::Selection);
}
-#if BOOST_FILESYSTEM_VERSION >= 3
-boost::filesystem::path qstringToBoostPath(const QString &path)
+fs::path qstringToBoostPath(const QString &path)
{
- return boost::filesystem::path(path.toStdString(), utf8);
+ return fs::path(path.toStdString(), utf8);
}
-QString boostPathToQString(const boost::filesystem::path &path)
+QString boostPathToQString(const fs::path &path)
{
return QString::fromStdString(path.string(utf8));
}
-#else
-#warning Conversion between boost path and QString can use invalid character encoding with boost_filesystem v2 and older
-boost::filesystem::path qstringToBoostPath(const QString &path)
-{
- return boost::filesystem::path(path.toStdString());
-}
-
-QString boostPathToQString(const boost::filesystem::path &path)
-{
- return QString::fromStdString(path.string());
-}
-#endif
QString formatDurationStr(int secs)
{
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index 5765b2ec4a..d10818d0c8 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -6,6 +6,7 @@
#define BITCOIN_QT_GUIUTIL_H
#include "amount.h"
+#include "fs.h"
#include <QEvent>
#include <QHeaderView>
@@ -16,8 +17,6 @@
#include <QTableView>
#include <QLabel>
-#include <boost/filesystem.hpp>
-
class QValidatedLineEdit;
class SendCoinsRecipient;
@@ -114,6 +113,9 @@ namespace GUIUtil
// Open debug.log
void openDebugLogfile();
+ // Open the config file
+ bool openBitcoinConf();
+
// Replace invalid default fonts with known good ones
void SubstituteFonts(const QString& language);
@@ -140,7 +142,7 @@ namespace GUIUtil
* Also makes sure the column widths are never larger than the table's viewport.
* In Qt, all columns are resizable from the right, but it's not intuitive resizing the last column from the right.
* Usually our second to last columns behave as if stretched, and when on strech mode, columns aren't resizable
- * interactively or programatically.
+ * interactively or programmatically.
*
* This helper object takes care of this issue.
*
@@ -177,16 +179,11 @@ namespace GUIUtil
bool GetStartOnSystemStartup();
bool SetStartOnSystemStartup(bool fAutoStart);
- /** Save window size and position */
- void saveWindowGeometry(const QString& strSetting, QWidget *parent);
- /** Restore window size and position */
- void restoreWindowGeometry(const QString& strSetting, const QSize &defaultSizeIn, QWidget *parent);
-
/* Convert QString to OS specific boost path through UTF-8 */
- boost::filesystem::path qstringToBoostPath(const QString &path);
+ fs::path qstringToBoostPath(const QString &path);
/* Convert OS specific boost path to QString through UTF-8 */
- QString boostPathToQString(const boost::filesystem::path &path);
+ QString boostPathToQString(const fs::path &path);
/* Convert seconds into a QString with days, hours, mins, secs */
QString formatDurationStr(int secs);
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index e0678f45fc..0ff95d8502 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -6,6 +6,7 @@
#include "config/bitcoin-config.h"
#endif
+#include "fs.h"
#include "intro.h"
#include "ui_intro.h"
@@ -13,8 +14,6 @@
#include "util.h"
-#include <boost/filesystem.hpp>
-
#include <QFileDialog>
#include <QSettings>
#include <QMessageBox>
@@ -23,9 +22,9 @@
static const uint64_t GB_BYTES = 1000000000LL;
/* Minimum free space (in GB) needed for data directory */
-static const uint64_t BLOCK_CHAIN_SIZE = 80;
+static const uint64_t BLOCK_CHAIN_SIZE = 150;
/* Minimum free space (in GB) needed for data directory when pruned; Does not include prune target */
-static const uint64_t CHAIN_STATE_SIZE = 2;
+static const uint64_t CHAIN_STATE_SIZE = 3;
/* Total required space (in GB) depending on user choice (prune, not prune) */
static uint64_t requiredSpace;
@@ -44,7 +43,7 @@ class FreespaceChecker : public QObject
Q_OBJECT
public:
- FreespaceChecker(Intro *intro);
+ explicit FreespaceChecker(Intro *intro);
enum Status {
ST_OK,
@@ -70,7 +69,6 @@ FreespaceChecker::FreespaceChecker(Intro *_intro)
void FreespaceChecker::check()
{
- namespace fs = boost::filesystem;
QString dataDirStr = intro->getPathToCheck();
fs::path dataDir = GUIUtil::qstringToBoostPath(dataDirStr);
uint64_t freeBytesAvailable = 0;
@@ -124,11 +122,34 @@ Intro::Intro(QWidget *parent) :
ui->setupUi(this);
ui->welcomeLabel->setText(ui->welcomeLabel->text().arg(tr(PACKAGE_NAME)));
ui->storageLabel->setText(ui->storageLabel->text().arg(tr(PACKAGE_NAME)));
- uint64_t pruneTarget = std::max<int64_t>(0, GetArg("-prune", 0));
+
+ ui->lblExplanation1->setText(ui->lblExplanation1->text()
+ .arg(tr(PACKAGE_NAME))
+ .arg(BLOCK_CHAIN_SIZE)
+ .arg(2009)
+ .arg(tr("Bitcoin"))
+ );
+ ui->lblExplanation2->setText(ui->lblExplanation2->text().arg(tr(PACKAGE_NAME)));
+
+ uint64_t pruneTarget = std::max<int64_t>(0, gArgs.GetArg("-prune", 0));
requiredSpace = BLOCK_CHAIN_SIZE;
- if (pruneTarget)
- requiredSpace = CHAIN_STATE_SIZE + std::ceil(pruneTarget * 1024 * 1024.0 / GB_BYTES);
- ui->sizeWarningLabel->setText(ui->sizeWarningLabel->text().arg(tr(PACKAGE_NAME)).arg(requiredSpace));
+ QString storageRequiresMsg = tr("At least %1 GB of data will be stored in this directory, and it will grow over time.");
+ if (pruneTarget) {
+ uint64_t prunedGBs = std::ceil(pruneTarget * 1024 * 1024.0 / GB_BYTES);
+ if (prunedGBs <= requiredSpace) {
+ requiredSpace = prunedGBs;
+ storageRequiresMsg = tr("Approximately %1 GB of data will be stored in this directory.");
+ }
+ ui->lblExplanation3->setVisible(true);
+ } else {
+ ui->lblExplanation3->setVisible(false);
+ }
+ requiredSpace += CHAIN_STATE_SIZE;
+ ui->sizeWarningLabel->setText(
+ tr("%1 will download and store a copy of the Bitcoin block chain.").arg(tr(PACKAGE_NAME)) + " " +
+ storageRequiresMsg.arg(requiredSpace) + " " +
+ tr("The wallet will also be stored in this directory.")
+ );
startThread();
}
@@ -167,18 +188,17 @@ QString Intro::getDefaultDataDirectory()
bool Intro::pickDataDirectory()
{
- namespace fs = boost::filesystem;
QSettings settings;
/* If data directory provided on command line, no need to look at settings
or show a picking dialog */
- if(!GetArg("-datadir", "").empty())
+ if(!gArgs.GetArg("-datadir", "").empty())
return true;
/* 1) Default data directory for operating system */
QString dataDir = getDefaultDataDirectory();
/* 2) Allow QSettings to override default dir */
dataDir = settings.value("strDataDir", dataDir).toString();
- if(!fs::exists(GUIUtil::qstringToBoostPath(dataDir)) || GetBoolArg("-choosedatadir", DEFAULT_CHOOSE_DATADIR) || settings.value("fReset", false).toBool() || GetBoolArg("-resetguisettings", false))
+ if(!fs::exists(GUIUtil::qstringToBoostPath(dataDir)) || gArgs.GetBoolArg("-choosedatadir", DEFAULT_CHOOSE_DATADIR) || settings.value("fReset", false).toBool() || gArgs.GetBoolArg("-resetguisettings", false))
{
/* If current default data directory does not exist, let the user choose one */
Intro intro;
@@ -194,7 +214,7 @@ bool Intro::pickDataDirectory()
}
dataDir = intro.getDataDirectory();
try {
- TryCreateDirectory(GUIUtil::qstringToBoostPath(dataDir));
+ TryCreateDirectories(GUIUtil::qstringToBoostPath(dataDir));
break;
} catch (const fs::filesystem_error&) {
QMessageBox::critical(0, tr(PACKAGE_NAME),
@@ -211,7 +231,7 @@ bool Intro::pickDataDirectory()
* (to be consistent with bitcoind behavior)
*/
if(dataDir != getDefaultDataDirectory())
- SoftSetArg("-datadir", GUIUtil::qstringToBoostPath(dataDir).string()); // use OS locale for path setting
+ gArgs.SoftSetArg("-datadir", GUIUtil::qstringToBoostPath(dataDir).string()); // use OS locale for path setting
return true;
}
diff --git a/src/qt/locale/bitcoin_af.ts b/src/qt/locale/bitcoin_af.ts
index 8cbf5aadc5..250fc6b5a2 100644
--- a/src/qt/locale/bitcoin_af.ts
+++ b/src/qt/locale/bitcoin_af.ts
@@ -74,6 +74,10 @@
<translation>&amp;Dupliseer Adres</translation>
</message>
<message>
+ <source>Copy &amp;Label</source>
+ <translation>Kopieer &amp;Etiket</translation>
+ </message>
+ <message>
<source>&amp;Edit</source>
<translation>&amp;Verander</translation>
</message>
@@ -200,6 +204,14 @@
<translation>U het die verkeerde wagwoord ingetik.</translation>
</message>
<message>
+ <source>Wallet decryption failed</source>
+ <translation>Beursie-dekripsie het misluk</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>Beursie wagwoordfrase is suksesvol verander.</translation>
+ </message>
+ <message>
<source>Warning: The Caps Lock key is on!</source>
<translation>WAARSKUWING: Outomatiese Kapitalisering is aktief op u sleutelbord!</translation>
</message>
@@ -207,6 +219,10 @@
<context>
<name>BanTableModel</name>
<message>
+ <source>IP/Netmask</source>
+ <translation>IP/Netmasker</translation>
+ </message>
+ <message>
<source>Banned Until</source>
<translation>Verban tot</translation>
</message>
@@ -214,6 +230,10 @@
<context>
<name>BitcoinGUI</name>
<message>
+ <source>Sign &amp;message...</source>
+ <translation>Teken &amp;boodskap...</translation>
+ </message>
+ <message>
<source>Synchronizing with network...</source>
<translation>Netwerk-sinkronisasie...</translation>
</message>
@@ -294,6 +314,18 @@
<translation>Oop &amp; URI...</translation>
</message>
<message>
+ <source>Click to disable network activity.</source>
+ <translation>Kliek om netwerkaktiwiteit af te skakel.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>Netwerkaktiwiteit gedeaktiveer.</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>Kliek om netwerkaktiwiteit weer aan te skakel.</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>Besig met herindeksering van blokke op hardeskyf...</translation>
</message>
@@ -310,6 +342,14 @@
<translation>Verander die wagwoord wat ek vir kodifikasie van my beursie gebruik</translation>
</message>
<message>
+ <source>&amp;Debug window</source>
+ <translation>&amp;Ontfout venster</translation>
+ </message>
+ <message>
+ <source>Open debugging and diagnostic console</source>
+ <translation>Maak ontfouting en diagnostiese konsole oop</translation>
+ </message>
+ <message>
<source>Bitcoin</source>
<translation>Bitcoin</translation>
</message>
@@ -382,10 +422,6 @@
<translation>Blokke op skyf word geprosesseer...</translation>
</message>
<message>
- <source>No block source available...</source>
- <translation>Geen blokbron beskikbaar...</translation>
- </message>
- <message>
<source>%1 behind</source>
<translation>%1 agter</translation>
</message>
@@ -477,16 +513,48 @@
<translation>Bevestig</translation>
</message>
<message>
+ <source>yes</source>
+ <translation>ja</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>nee</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation>Kan verskil met +/- %1 satoshi(s) per invoer.</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(geen etiket)</translation>
</message>
- </context>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation>verander van %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(verander)</translation>
+ </message>
+</context>
<context>
<name>EditAddressDialog</name>
<message>
<source>Edit Address</source>
<translation>Wysig Adres</translation>
</message>
+ <message>
+ <source>&amp;Label</source>
+ <translation>&amp;Etiket</translation>
+ </message>
+ <message>
+ <source>&amp;Address</source>
+ <translation>&amp;Adres</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Kon beursie nie oopsluit nie.</translation>
+ </message>
</context>
<context>
<name>FreespaceChecker</name>
@@ -529,6 +597,10 @@
<translation>Welkom by %1.</translation>
</message>
<message>
+ <source>Error: Specified data directory "%1" cannot be created.</source>
+ <translation>Fout: Gespesifiseerde dataleêr "%1" kon nie geskep word nie.</translation>
+ </message>
+ <message>
<source>Error</source>
<translation>Fout</translation>
</message>
@@ -566,10 +638,30 @@
<translation>Alle kliëntopsies na verstek terugstel.</translation>
</message>
<message>
+ <source>&amp;Network</source>
+ <translation>&amp;Netwerk</translation>
+ </message>
+ <message>
+ <source>W&amp;allet</source>
+ <translation>B&amp;eursie</translation>
+ </message>
+ <message>
<source>Expert</source>
<translation>Kenner</translation>
</message>
<message>
+ <source>Enable coin &amp;control features</source>
+ <translation>Bemagtig munt &amp;beheer funksies.</translation>
+ </message>
+ <message>
+ <source>&amp;Port:</source>
+ <translation>&amp;Poort:</translation>
+ </message>
+ <message>
+ <source>IPv4</source>
+ <translation>IPv4</translation>
+ </message>
+ <message>
<source>IPv6</source>
<translation>IPv6</translation>
</message>
@@ -578,6 +670,14 @@
<translation>Tor</translation>
</message>
<message>
+ <source>&amp;OK</source>
+ <translation>&amp;OK</translation>
+ </message>
+ <message>
+ <source>&amp;Cancel</source>
+ <translation>&amp;Kanselleer</translation>
+ </message>
+ <message>
<source>default</source>
<translation>verstek</translation>
</message>
diff --git a/src/qt/locale/bitcoin_af_ZA.ts b/src/qt/locale/bitcoin_af_ZA.ts
index 1db5008384..432e8c3faf 100644
--- a/src/qt/locale/bitcoin_af_ZA.ts
+++ b/src/qt/locale/bitcoin_af_ZA.ts
@@ -6,13 +6,73 @@
<translation>Skep 'n nuwe adres</translation>
</message>
<message>
+ <source>&amp;New</source>
+ <translation>&amp;Nuwe</translation>
+ </message>
+ <message>
<source>Copy the currently selected address to the system clipboard</source>
<translation>Maak 'n kopie van die huidige adres na die stelsel klipbord</translation>
</message>
<message>
+ <source>&amp;Copy</source>
+ <translation>&amp;Kopie</translation>
+ </message>
+ <message>
+ <source>Delete the currently selected address from the list</source>
+ <translation>Verwyder die huidiglik gekieste address van die lys</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Voer inligting uit van die huidige blad na n lêer</translation>
+ </message>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;Uitvoer</translation>
+ </message>
+ <message>
<source>&amp;Delete</source>
<translation>&amp;Verwyder</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Kies die address na wie die muntstukke gestuur moet word</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>K&amp;ies</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Stuur adresse</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Ontvang adresse</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Kopie adres</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Kopie &amp;Etiket</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Wysig</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Voer adres lys uit</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Koma geskeide lêers (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Uitvoering Misluk</translation>
+ </message>
</context>
<context>
<name>AddressTableModel</name>
@@ -411,6 +471,14 @@
<translation>Kopieer bedrag</translation>
</message>
<message>
+ <source>%1 to %2</source>
+ <translation>%1 tot %2</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>of</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(geen etiket)</translation>
</message>
@@ -641,6 +709,10 @@
<translation>Kopieer bedrag</translation>
</message>
<message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Koma geskeide lêers (*.csv)</translation>
+ </message>
+ <message>
<source>Date</source>
<translation>Datum</translation>
</message>
@@ -661,6 +733,10 @@
<translation>ID</translation>
</message>
<message>
+ <source>Exporting Failed</source>
+ <translation>Uitvoering Misluk</translation>
+ </message>
+ <message>
<source>Range:</source>
<translation>Reeks:</translation>
</message>
@@ -684,6 +760,14 @@
</context>
<context>
<name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;Uitvoer</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Voer inligting uit van die huidige blad na n lêer</translation>
+ </message>
</context>
<context>
<name>bitcoin-core</name>
diff --git a/src/qt/locale/bitcoin_ar.ts b/src/qt/locale/bitcoin_ar.ts
index 15c5158f21..68c69038fd 100644
--- a/src/qt/locale/bitcoin_ar.ts
+++ b/src/qt/locale/bitcoin_ar.ts
@@ -314,6 +314,18 @@
<translation>افتح &amp;URI...</translation>
</message>
<message>
+ <source>Click to disable network activity.</source>
+ <translation>اضغط لإلغاء تفعيل الشبكه</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>تم إلغاء تفعيل الشبكه</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>اضغط لتفعيل الشبكه مره أخرى</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>إعادة الفهرسة الكتل على القرص ...</translation>
</message>
@@ -422,10 +434,6 @@
<translation>معالجة الكتل على القرص...</translation>
</message>
<message>
- <source>No block source available...</source>
- <translation>لا يوجد أي مصدر الكتلة</translation>
- </message>
- <message>
<source>%1 behind</source>
<translation>خلف %1</translation>
</message>
@@ -513,7 +521,11 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>المحفظة &lt;b&gt;مشفرة&lt;/b&gt; و &lt;b&gt;مقفلة&lt;/b&gt; حاليا</translation>
</message>
- </context>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>خطأ فادح حدث . لا يمكن اتمام بيتكوين بامان سيتم الخروج</translation>
+ </message>
+</context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -613,6 +625,10 @@
<translation>نسخ بعد الرسوم</translation>
</message>
<message>
+ <source>Copy bytes</source>
+ <translation>نسخ البايتات </translation>
+ </message>
+ <message>
<source>Copy change</source>
<translation>نسخ التعديل</translation>
</message>
@@ -800,6 +816,10 @@
<translation>نمودج</translation>
</message>
<message>
+ <source>Unknown...</source>
+ <translation>غير معرف</translation>
+ </message>
+ <message>
<source>Hide</source>
<translation>إخفاء</translation>
</message>
@@ -1367,6 +1387,10 @@
<translation>نسخ بعد الرسوم</translation>
</message>
<message>
+ <source>Copy bytes</source>
+ <translation>نسخ البايتات </translation>
+ </message>
+ <message>
<source>Copy change</source>
<translation>نسخ التعديل</translation>
</message>
diff --git a/src/qt/locale/bitcoin_be_BY.ts b/src/qt/locale/bitcoin_be_BY.ts
index d2c52f2c16..62f2ffc9e6 100644
--- a/src/qt/locale/bitcoin_be_BY.ts
+++ b/src/qt/locale/bitcoin_be_BY.ts
@@ -390,10 +390,6 @@
<translation>Опцыі каманднага радка</translation>
</message>
<message>
- <source>No block source available...</source>
- <translation>Крыніца блокаў недасяжная...</translation>
- </message>
- <message>
<source>%1 behind</source>
<translation>%1 таму</translation>
</message>
diff --git a/src/qt/locale/bitcoin_bg.ts b/src/qt/locale/bitcoin_bg.ts
index 5a0fd2aec2..37b7f8532a 100644
--- a/src/qt/locale/bitcoin_bg.ts
+++ b/src/qt/locale/bitcoin_bg.ts
@@ -314,6 +314,18 @@
<translation>Отвори &amp;URI...</translation>
</message>
<message>
+ <source>Click to disable network activity.</source>
+ <translation>Натиснете за деактивиране на мрежата</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>Мрежата деактивирана</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>Натиснете за повторно активиране на мрежата</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>Повторно индексиране на блоковете на диска...</translation>
</message>
@@ -422,10 +434,6 @@
<translation>Обработване на блокове на диска...</translation>
</message>
<message>
- <source>No block source available...</source>
- <translation>Липсва източник на блоковете...</translation>
- </message>
- <message>
<source>%1 behind</source>
<translation>%1 зад</translation>
</message>
@@ -462,6 +470,10 @@
<translation>%1 клиент</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>Свързване с пиъри</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>Зарежда блокове...</translation>
</message>
@@ -799,6 +811,10 @@
<translation>Добре дошли в %1.</translation>
</message>
<message>
+ <source>As this is the first time the program is launched, you can choose where %1 will store its data.</source>
+ <translation>Програмата се стартира за първи път вие може да изберете къде %1 ще се запаметят данните.</translation>
+ </message>
+ <message>
<source>Use the default data directory</source>
<translation>Използване на директория по подразбиране</translation>
</message>
@@ -822,6 +838,10 @@
<translation>Време на последния блок</translation>
</message>
<message>
+ <source>calculating...</source>
+ <translation>Изчисляване...</translation>
+ </message>
+ <message>
<source>Hide</source>
<translation>Скрий</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ca.ts b/src/qt/locale/bitcoin_ca.ts
index c09d857632..84f51d18a8 100644
--- a/src/qt/locale/bitcoin_ca.ts
+++ b/src/qt/locale/bitcoin_ca.ts
@@ -441,10 +441,6 @@
<source>Processing blocks on disk...</source>
<translation>S'estan processant els blocs al disc...</translation>
</message>
- <message>
- <source>No block source available...</source>
- <translation>No hi ha cap font de bloc disponible...</translation>
- </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation><numerusform>S'ha processat %n bloc de l'historial de transacció.</numerusform><numerusform>S'han processat %n blocs de l'historial de transacció.</numerusform></translation>
@@ -2822,10 +2818,6 @@
<translation>Poda: la darrera sincronització del moneder va més enllà de les dades podades. Cal que activeu -reindex (baixeu tota la cadena de blocs de nou en cas de node podat)</translation>
</message>
<message>
- <source>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, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Reduïu els requisits d'emmagatzematge podant (suprimint) els blocs antics. Aquest mode és incompatible amb -txindex i -rescan. Avís: la reversió d'aquest paràmetre implica haver de tornar a baixar la cadena de blocs sencera. (per defecte: 0 = inhabilita la poda de blocs, &gt;%u = mida objectiu en MiB per utilitzar en els fitxers de blocs)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Els rescanejos no són possible en el mode de poda. Caldrà que utilitzeu -reindex, que tornarà a baixar la cadena de blocs sencera.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ca@valencia.ts b/src/qt/locale/bitcoin_ca@valencia.ts
index c4748c0afa..0123f8faab 100644
--- a/src/qt/locale/bitcoin_ca@valencia.ts
+++ b/src/qt/locale/bitcoin_ca@valencia.ts
@@ -394,10 +394,6 @@
<translation>Opcions de la &amp;línia d'ordes</translation>
</message>
<message>
- <source>No block source available...</source>
- <translation>No hi ha cap font de bloc disponible...</translation>
- </message>
- <message>
<source>%1 behind</source>
<translation>%1 darrere</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ca_ES.ts b/src/qt/locale/bitcoin_ca_ES.ts
index 838190b10e..2dd724c442 100644
--- a/src/qt/locale/bitcoin_ca_ES.ts
+++ b/src/qt/locale/bitcoin_ca_ES.ts
@@ -3,7 +3,7 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation>Feu clic dret per a editar l'adreça o l'etiqueta</translation>
+ <translation>Feu clic dret per a editar l'adreça o l'etiquetaccn</translation>
</message>
<message>
<source>Create a new address</source>
@@ -441,10 +441,6 @@
<source>Processing blocks on disk...</source>
<translation>S'estan processant els blocs al disc...</translation>
</message>
- <message>
- <source>No block source available...</source>
- <translation>No hi ha cap font de bloc disponible...</translation>
- </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation><numerusform>S'ha processat %n bloc de l'historial de transacció.</numerusform><numerusform>S'han processat %n blocs de l'historial de transacció.</numerusform></translation>
@@ -882,6 +878,10 @@
<translation>Formulari</translation>
</message>
<message>
+ <source>Unknown...</source>
+ <translation>Desconegut...</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation>Últim temps de bloc</translation>
</message>
@@ -1386,7 +1386,11 @@
</context>
<context>
<name>QObject::QObject</name>
- </context>
+ <message>
+ <source>Error: %1</source>
+ <translation>Avís: %1</translation>
+ </message>
+</context>
<context>
<name>QRImageWidget</name>
<message>
@@ -2342,6 +2346,10 @@
<translation>%1/fora de línia</translation>
</message>
<message>
+ <source>abandoned</source>
+ <translation>abandonada</translation>
+ </message>
+ <message>
<source>%1/unconfirmed</source>
<translation>%1/sense confirmar</translation>
</message>
@@ -2472,7 +2480,11 @@
<source>This pane shows a detailed description of the transaction</source>
<translation>Aquest panell mostra una descripció detallada de la transacció</translation>
</message>
- </context>
+ <message>
+ <source>Details for %1</source>
+ <translation>Detalls per %1</translation>
+ </message>
+</context>
<context>
<name>TransactionTableModel</name>
<message>
@@ -2663,6 +2675,10 @@
<translation>Copia la transacció crua</translation>
</message>
<message>
+ <source>Copy full transaction details</source>
+ <translation>Copia els detalls complets de la transacció</translation>
+ </message>
+ <message>
<source>Edit label</source>
<translation>Editar etiqueta</translation>
</message>
@@ -2822,10 +2838,6 @@
<translation>Poda: la darrera sincronització del moneder va més enllà de les dades podades. Cal que activeu -reindex (baixeu tota la cadena de blocs de nou en cas de node podat)</translation>
</message>
<message>
- <source>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, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Reduïu els requisits d'emmagatzematge podant (suprimint) els blocs antics. Aquest mode és incompatible amb -txindex i -rescan. Avís: la reversió d'aquest paràmetre implica haver de tornar a baixar la cadena de blocs sencera. (per defecte: 0 = inhabilita la poda de blocs, &gt;%u = mida objectiu en MiB per utilitzar en els fitxers de blocs)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Els rescanejos no són possible en el mode de poda. Caldrà que utilitzeu -reindex, que tornarà a baixar la cadena de blocs sencera.</translation>
</message>
@@ -3150,6 +3162,10 @@
<translation>Avís</translation>
</message>
<message>
+ <source>Warning: unknown new rules activated (versionbit %i)</source>
+ <translation>Avís: regles noves desconegudes activades (versionbit %i)</translation>
+ </message>
+ <message>
<source>Zapping all transactions from wallet...</source>
<translation>Se suprimeixen totes les transaccions del moneder...</translation>
</message>
diff --git a/src/qt/locale/bitcoin_cs.ts b/src/qt/locale/bitcoin_cs.ts
index 3b5d7947f6..f38c425137 100644
--- a/src/qt/locale/bitcoin_cs.ts
+++ b/src/qt/locale/bitcoin_cs.ts
@@ -330,6 +330,10 @@
<translation>Kliknutím opět umožníš spojení do sítě.</translation>
</message>
<message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>Synchronizuji záhlaví bloků (%1 %)…</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>Vytvářím nový index bloků na disku...</translation>
</message>
@@ -441,10 +445,6 @@
<source>Processing blocks on disk...</source>
<translation>Zpracovávám bloky na disku...</translation>
</message>
- <message>
- <source>No block source available...</source>
- <translation>Není dostupný žádný zdroj bloků...</translation>
- </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation><numerusform>Zpracován %n blok transakční historie.</numerusform><numerusform>Zpracovány %n bloky transakční historie.</numerusform><numerusform>Zpracováno %n bloků transakční historie.</numerusform></translation>
@@ -486,6 +486,10 @@
<translation>%1 klient</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>Připojuji se…</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>Stahuji...</translation>
</message>
@@ -2205,6 +2209,14 @@
<translation>Upozornění: Neznámá adresa pro drobné</translation>
</message>
<message>
+ <source>Confirm custom change address</source>
+ <translation>Potvrď vlastní adresu pro drobné</translation>
+ </message>
+ <message>
+ <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source>
+ <translation>Adresa, kterou jsi zvolil pro drobné, není součástí této peněženky. Potenciálně všechny prostředky z tvé peněženky mohou být na tuto adresu odeslány. Souhlasíš, aby se tak stalo?</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(bez označení)</translation>
</message>
@@ -3022,10 +3034,6 @@
<translation>Prořezávání: poslední synchronizace peněženky proběhla před už prořezanými daty. Je třeba provést -reindex (tedy v případě prořezávacího režimu stáhnout znovu celý řetězec bloků)</translation>
</message>
<message>
- <source>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, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Omezit nároky na úložný prostor prořezáváním (mazáním) starých bloků. Tento režim není slučitelný s -txindex ani -rescan. Upozornění: opětovná změna tohoto nastavení bude vyžadovat nové stažení celého řetězce bloků. (výchozí: 0 = bloky neprořezávat, &gt;%u = cílová velikost souborů s bloky, v MiB)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>V prořezávacím režimu není možné přeskenovávat řetězec bloků. Musíš provést -reindex, což znovu stáhne celý řetězec bloků.</translation>
</message>
@@ -3090,6 +3098,14 @@
<translation>Spustit příkaz, když se objeví transakce týkající se peněženky (%s se v příkazu nahradí za TxID)</translation>
</message>
<message>
+ <source>Extra transactions to keep in memory for compact block reconstructions (default: %u)</source>
+ <translation>Počet extra transakcí, které se mají držet v paměti pro účely rekonstrukce kompaktních bloků (výchozí: %u)</translation>
+ </message>
+ <message>
+ <source>If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)</source>
+ <translation>Pokud je tenhle blok v řetězci, tak předpokládat, že on i jeho následníci jsou platní, a potenciálně přeskočit ověřování jejich skriptů (0 = ověřovat vše, výchozí: %s, testnet: %s)</translation>
+ </message>
+ <message>
<source>Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)</source>
<translation>Maximální povolené seřizování času mediánem časů protějšků. Místní vnímání času může být ovlivněno protějšky, a to dopředu nebo dozadu až o toto množství. (výchozí: %u vteřin)</translation>
</message>
@@ -3106,6 +3122,14 @@
<translation>Prosíme, zapoj se nebo přispěj, pokud ti %s přijde užitečný. Více informací o programu je na %s.</translation>
</message>
<message>
+ <source>Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, &gt;%u = automatically prune block files to stay under the specified target size in MiB)</source>
+ <translation>Omezit nároky na úložný prostor prořezáváním (mazáním) starých bloků. Tato volba také umožní použít RPC volání pruneblockchain ke smazání konkrétních bloků a dále automatické prořezávání starých bloků, pokud je zadána cílová velikost souborů s bloky v MiB. Tento režim není slučitelný s -txindex ani -rescan. Upozornění: opětovná změna tohoto nastavení bude vyžadovat nové stažení celého řetězce bloků. (výchozí: 0 = bloky neprořezávat, 1 = povolit ruční prořezávání skrze RPC, &gt;%u = automatické prořezávání bloků tak, aby byla udržena cílová velikost souborů s bloky, v MiB)</translation>
+ </message>
+ <message>
+ <source>Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)</source>
+ <translation>Nastavit nejnižší akceptovatelný poplatek (v %s/kB) pro transakce, které mají být zahrnuty do nových bloků. (výchozí: %s)</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>Nastavení počtu vláken pro verifikaci skriptů (%u až %d, 0 = automaticky, &lt;0 = nechat daný počet jader volný, výchozí: %d)</translation>
</message>
@@ -3126,6 +3150,10 @@
<translation>Použít UPnP k namapování naslouchacího portu (výchozí: 1, pokud naslouchá a nepoužívá -proxy)</translation>
</message>
<message>
+ <source>Username and hashed password for JSON-RPC connections. The field &lt;userpw&gt; comes in the format: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=&lt;USERNAME&gt;/rpcpassword=&lt;PASSWORD&gt; pair of arguments. This option can be specified multiple times</source>
+ <translation>Uživatelské jméno a zahašované heslo pro JSON-RPC spojení. Pole &lt;userpw&gt; má formát: &lt;UŽIVATELSKÉ_JMÉNO&gt;:&lt;SŮL&gt;$&lt;HAŠ&gt;. Pomocný pythonní skript je přiložen v share/rpcuser. Klient se pak už připojuje normálně pomocí páru argumentů rpcuser=&lt;UŽIVATELSKÉ_JMÉNO&gt;/rpcpassword=&lt;HESLO&gt;. Tuto volbu lze použít i vícekrát</translation>
+ </message>
+ <message>
<source>Wallet will not create transactions that violate mempool chain limits (default: %u)</source>
<translation>Peněženka nebude vytvářet transakce, které by porušovaly limity transakčního zásobníku na řetězce (výchozí: %u)</translation>
</message>
diff --git a/src/qt/locale/bitcoin_da.ts b/src/qt/locale/bitcoin_da.ts
index 0b49b5aefc..bc3fcb278e 100644
--- a/src/qt/locale/bitcoin_da.ts
+++ b/src/qt/locale/bitcoin_da.ts
@@ -3,7 +3,7 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation>Højreklik for at redigere adresse eller mærke</translation>
+ <translation>Højreklik for at redigere adresse eller mærkat</translation>
</message>
<message>
<source>Create a new address</source>
@@ -330,6 +330,10 @@
<translation>Klik for a aktivere netværksaktivitet igen.</translation>
</message>
<message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>Synkroniserer hoveder (%1%)…</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>Genindekserer blokke på disken…</translation>
</message>
@@ -441,10 +445,6 @@
<source>Processing blocks on disk...</source>
<translation>Bearbejder blokke på disken…</translation>
</message>
- <message>
- <source>No block source available...</source>
- <translation>Ingen blokkilde tilgængelig…</translation>
- </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation><numerusform>Bearbejdede %n blok med transaktionshistorik.</numerusform><numerusform>Bearbejdede %n blokke med transaktionshistorik.</numerusform></translation>
@@ -486,6 +486,10 @@
<translation>%1-klient</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>Forbinder til knuder…</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>Indhenter…</translation>
</message>
@@ -600,7 +604,7 @@
</message>
<message>
<source>Received with label</source>
- <translation>Modtaget med mærke</translation>
+ <translation>Modtaget med mærkat</translation>
</message>
<message>
<source>Received with address</source>
@@ -3030,10 +3034,6 @@
<translation>Beskæring: Seneste synkronisering rækker udover beskårne data. Du er nødt til at bruge -reindex (downloade hele blokkæden igen i fald af beskåret knude)</translation>
</message>
<message>
- <source>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, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Reducér lagringskravene ved at beskære (slette) gamle blokke. Denne tilstand er ikke kompatibel med -txindex og -rescan. Advarsel: Fortrydelse af denne indstilling kræver gendownload af hele blokkæden. (standard: 0 = deaktivér beskæring af blokke, &gt;%u = målstørrelse i MiB der skal bruges på blokfiler)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Genindlæsninger er ikke mulige i beskåret tilstand. Du er nødt til at bruge -reindex, hvilket vil downloade hele blokkæden igen.</translation>
</message>
@@ -3098,6 +3098,14 @@
<translation>Udfør kommando, når en transaktion i tegnebogen ændres (%s i kommandoen erstattes med TxID)</translation>
</message>
<message>
+ <source>Extra transactions to keep in memory for compact block reconstructions (default: %u)</source>
+ <translation>Ekstra transaktioner, der skal beholdes i hukommelsen til kompakte blokgenopbygninger (standard: %u)</translation>
+ </message>
+ <message>
+ <source>If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)</source>
+ <translation>Hvis denne blok er i kæden, så antag at den og dens forgængere er gyldige, og spring potentielt deres scriptverificering over (0 for at verificere alle, standard: %s, testnet: %s)</translation>
+ </message>
+ <message>
<source>Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)</source>
<translation>Justering af maksimalt tilladt gennemsnitlig afvigelse fra peer-tid. Den lokale opfattelse af tid kan blive påvirket frem eller tilbage af peers med denne mængde tid. (standard: %u sekunder)</translation>
</message>
@@ -3114,6 +3122,14 @@
<translation>Overvej venligst at bidrage til udviklingen, hvis du finder %s brugbar. Besøg %s for yderligere information om softwaren.</translation>
</message>
<message>
+ <source>Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, &gt;%u = automatically prune block files to stay under the specified target size in MiB)</source>
+ <translation>Reducér pladskravene ved at beskære (slette, “prune”) gamle blokke. Dette tillader pruneblockchain-RPC'en at blive kaldt for at slette specifikke blokke, og det aktiverer automatisk beskæring af gamle blokke, hvis en målstørrelse i MiB er angivet. Denne tilstand er ikke kompatibel med -txindex og -rescan. Advarsel: Fortrydelse af denne indstilling kræver download af hele blokkæden igen. (standard: 0 = slå beskæring af blokke fra, 1 = tillad manuel beskæring via RPC, &gt;%u = beskær automatisk blokfiler for at bliver under den angivne målstørrelse i MiB)</translation>
+ </message>
+ <message>
+ <source>Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)</source>
+ <translation>Sæt den laveste gebyrrate (i %s/kB) for transaktioner, der skal inkluderes i blokoprettelse. (standard: %s)</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>Sæt antallet af scriptverificeringstråde (%u til %d, 0 = auto, &lt;0 = efterlad det antal kernet fri, standard: %d)</translation>
</message>
diff --git a/src/qt/locale/bitcoin_de.ts b/src/qt/locale/bitcoin_de.ts
index 1dfd77cf61..dcd2286005 100644
--- a/src/qt/locale/bitcoin_de.ts
+++ b/src/qt/locale/bitcoin_de.ts
@@ -79,7 +79,7 @@
</message>
<message>
<source>&amp;Edit</source>
- <translation>&amp;Editieren</translation>
+ <translation>B&amp;earbeiten</translation>
</message>
<message>
<source>Export Address List</source>
@@ -133,7 +133,7 @@
</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>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>
+ <translation>Geben Sie die neue Passphrase für die Brieftasche 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>Encrypt wallet</source>
@@ -141,7 +141,7 @@
</message>
<message>
<source>This operation needs your wallet passphrase to unlock the wallet.</source>
- <translation>Dieser Vorgang benötigt ihre Passphrase, um die Wallet zu entsperren.</translation>
+ <translation>Dieser Vorgang benötigt ihre Passphrase, um die Brieftasche zu entsperren.</translation>
</message>
<message>
<source>Unlock wallet</source>
@@ -149,11 +149,11 @@
</message>
<message>
<source>This operation needs your wallet passphrase to decrypt the wallet.</source>
- <translation>Dieser Vorgang benötigt Ihre Passphrase, um die Wallet zu entschlüsseln.</translation>
+ <translation>Dieser Vorgang benötigt Ihre Passphrase, um die Brieftasche zu entschlüsseln.</translation>
</message>
<message>
<source>Decrypt wallet</source>
- <translation>Wallet entschlüsseln</translation>
+ <translation>Brieftasche entschlüsseln</translation>
</message>
<message>
<source>Change passphrase</source>
@@ -161,39 +161,39 @@
</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>
+ <translation>Geben Sie die alte und neue Brieftschen-Passphrase ein.</translation>
</message>
<message>
<source>Confirm wallet encryption</source>
- <translation>Wallet-Verschlüsselung bestätigen</translation>
+ <translation>Brieftaschen-Verschlüsselung bestätigen</translation>
</message>
<message>
<source>Warning: If you encrypt your wallet and lose your passphrase, you will &lt;b&gt;LOSE ALL OF YOUR BITCOINS&lt;/b&gt;!</source>
- <translation>Warnung: Wenn Sie Ihre Wallet verschlüsseln und Ihre Passphrase verlieren, werden Sie &lt;b&gt;alle Ihre Bitcoins verlieren&lt;/b&gt;!</translation>
+ <translation>Warnung: Wenn Sie Ihre Brieftasche verschlüsseln und Ihre Passphrase verlieren, werden Sie &lt;b&gt;alle Ihre Bitcoins verlieren&lt;/b&gt;!</translation>
</message>
<message>
<source>Are you sure you wish to encrypt your wallet?</source>
- <translation>Sind Sie sich sicher, dass Sie Ihre Wallet verschlüsseln möchten?</translation>
+ <translation>Sind Sie sich sicher, dass Sie Ihre Brieftasche verschlüsseln möchten?</translation>
</message>
<message>
<source>Wallet encrypted</source>
- <translation>Wallet verschlüsselt</translation>
+ <translation>Brieftasche verschlüsselt</translation>
</message>
<message>
<source>%1 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>%1 wird jetzt beendet, um den Verschlüsselungsprozess abzuschließen. Bitte beachten Sie, dass die Wallet-Verschlüsselung nicht vollständig vor Diebstahl Ihrer Bitcoins durch Schadprogramme schützt, die Ihren Computer befällt.</translation>
+ <translation>%1 wird jetzt beendet, um den Verschlüsselungsprozess abzuschließen. Bitte beachten Sie, dass die Brieftaschen-Verschlüsselung nicht vollständig vor Diebstahl Ihrer Bitcoins durch Schadprogramme schützt, die Ihren Computer befällt.</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>
+ <translation>WICHTIG: Alle vorherigen Brieftaschen-Sicherungen sollten durch die neu erzeugte, verschlüsselte Brieftasche ersetzt werden. Aus Sicherheitsgründen werden vorherige Sicherungen der unverschlüsselten Brieftasche nutzlos, sobald Sie die neue, verschlüsselte Brieftasche verwenden.</translation>
</message>
<message>
<source>Wallet encryption failed</source>
- <translation>Wallet-Verschlüsselung fehlgeschlagen</translation>
+ <translation>Brieftaschen-Verschlüsselung fehlgeschlagen</translation>
</message>
<message>
<source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
- <translation>Die Wallet-Verschlüsselung ist aufgrund eines internen Fehlers fehlgeschlagen. Ihre Wallet wurde nicht verschlüsselt.</translation>
+ <translation>Die Brieftaschen-Verschlüsselung ist aufgrund eines internen Fehlers fehlgeschlagen. Ihre Brieftasche wurde nicht verschlüsselt.</translation>
</message>
<message>
<source>The supplied passphrases do not match.</source>
@@ -201,19 +201,19 @@
</message>
<message>
<source>Wallet unlock failed</source>
- <translation>Wallet-Entsperrung fehlgeschlagen</translation>
+ <translation>Brieftaschen-Entsperrung fehlgeschlagen</translation>
</message>
<message>
<source>The passphrase entered for the wallet decryption was incorrect.</source>
- <translation>Die eingegebene Passphrase zur Wallet-Entschlüsselung war nicht korrekt.</translation>
+ <translation>Die eingegebene Passphrase zur Brieftaschen-Entschlüsselung war nicht korrekt.</translation>
</message>
<message>
<source>Wallet decryption failed</source>
- <translation>Wallet-Entschlüsselung fehlgeschlagen</translation>
+ <translation>Brieftaschen-Entschlüsselung fehlgeschlagen</translation>
</message>
<message>
<source>Wallet passphrase was successfully changed.</source>
- <translation>Die Wallet-Passphrase wurde erfolgreich geändert.</translation>
+ <translation>Die Brieftaschen-Passphrase wurde erfolgreich geändert.</translation>
</message>
<message>
<source>Warning: The Caps Lock key is on!</source>
@@ -330,6 +330,10 @@
<translation>Klicken zum Aktivieren der Netzwerkaktivität.</translation>
</message>
<message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>Kopfdaten werden synchronisiert (%1%)...</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>Reindiziere Blöcke auf Datenträger...</translation>
</message>
@@ -435,16 +439,12 @@
</message>
<message>
<source>Indexing blocks on disk...</source>
- <translation>Reindiziere Blöcke auf Datenträger...</translation>
+ <translation>Indiziere Blöcke auf Datenträger...</translation>
</message>
<message>
<source>Processing blocks on disk...</source>
<translation>Verarbeite Blöcke auf Datenträger...</translation>
</message>
- <message>
- <source>No block source available...</source>
- <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>
@@ -486,6 +486,10 @@
<translation>%1 Client</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>Verbinde mit Netzwerk...</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>Hole auf...</translation>
</message>
@@ -632,7 +636,7 @@
</message>
<message>
<source>Copy transaction ID</source>
- <translation>Transaktionskennung kopieren</translation>
+ <translation>Transaktions-ID kopieren</translation>
</message>
<message>
<source>Lock unspent</source>
@@ -656,7 +660,7 @@
</message>
<message>
<source>Copy bytes</source>
- <translation>Byte kopieren</translation>
+ <translation>Bytes kopieren</translation>
</message>
<message>
<source>Copy dust</source>
@@ -747,7 +751,7 @@
</message>
<message>
<source>Could not unlock wallet.</source>
- <translation>Wallet konnte nicht entsperrt werden.</translation>
+ <translation>Brieftasche konnte nicht entsperrt werden.</translation>
</message>
<message>
<source>New key generation failed.</source>
@@ -813,7 +817,7 @@
</message>
<message>
<source>Set language, for example "de_DE" (default: system locale)</source>
- <translation>Sprache einstellen, zum Beispiel "de_DE" (default: system locale)</translation>
+ <translation>Sprache einstellen, zum Beispiel "de_DE" (Standard: Systemgebietsschema)</translation>
</message>
<message>
<source>Start minimized</source>
@@ -821,7 +825,7 @@
</message>
<message>
<source>Set SSL root certificates for payment request (default: -system-)</source>
- <translation>SSL-Wurzelzertifikate für Zahlungsanforderungen festlegen (Standard: -system-)</translation>
+ <translation>SSL-Wurzelzertifikate für Zahlungsanforderungen festlegen (Standard: Systemstandard)</translation>
</message>
<message>
<source>Show splash screen on startup (default: %u)</source>
@@ -882,6 +886,14 @@
<translation>Formular</translation>
</message>
<message>
+ <source>Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source>
+ <translation>Neueste Transaktionen werden eventuell noch nicht angezeigt, daher könnte Ihr Kontostand veraltet sein. Er wird korrigiert, sobald Ihr Wallet die Synchronisation mit dem Bitcoin-Netzwerk erfolgreich abgeschlossen. Details dazu finden sich weiter unten.</translation>
+ </message>
+ <message>
+ <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source>
+ <translation>Versuche, Bitcoins aus noch nicht angezeigten Transaktionen auszugeben, werden vom Netzwerk nicht akzeptiert.</translation>
+ </message>
+ <message>
<source>Number of blocks left</source>
<translation>Anzahl verbleibender Blöcke</translation>
</message>
@@ -2193,6 +2205,14 @@
<translation>Warnung: Unbekannte Wechselgeld-Adresse</translation>
</message>
<message>
+ <source>Confirm custom change address</source>
+ <translation>Bestätige benutzerdefinierte Wechselgeld-Adresse</translation>
+ </message>
+ <message>
+ <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source>
+ <translation>Die ausgewählte Wechselgeld-Adresse ist nicht Bestandteil dieses Wallets. Einige oder alle Mittel aus Ihrem Wallet könnten an diese Adresse gesendet werden. Wollen Sie das wirklich?</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(keine Bezeichnung)</translation>
</message>
@@ -2990,6 +3010,10 @@
<translation>Eingehende Verbindungen annehmen (Standard: 1, wenn nicht -proxy oder -connect/-noconnect)</translation>
</message>
<message>
+ <source>Connect only to the specified node(s); -noconnect or -connect=0 alone to disable automatic connections</source>
+ <translation>Verbindungen nur zu spezifizierten Node(s); verwenden Sie -noconnect oder -connect=0 alleine um automatische Verbindungen zu deaktivieren</translation>
+ </message>
+ <message>
<source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
<translation>Veröffentlicht unter der MIT-Softwarelizenz, siehe beiligende Datei %s oder %s.</translation>
</message>
@@ -3006,10 +3030,6 @@
<translation>Prune (Kürzung): Die letzte Syncronisation der Wallet liegt vor gekürzten (gelöschten) Blöcken. Es ist ein -reindex (download der gesamten Blockkette) notwendig.</translation>
</message>
<message>
- <source>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, &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 ist nicht mit -txindex und -rescan 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>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Rescans sind im pruned mode nicht möglich. Ein -reindex ist notwendig, welcher die gesmate Blockkette erneut herunterlädt.</translation>
</message>
@@ -3062,6 +3082,10 @@
<translation>Alle Wallet-Transaktionen löschen und nur diese Teilbereiche der Blockkette durch -rescan beim Starten wiederherstellen</translation>
</message>
<message>
+ <source>Error loading %s: You can't enable HD on a already existing non-HD wallet</source>
+ <translation>Fehler beim Laden von %s: Sie können HD nicht aktivieren da sie derzeit eine nicht HD Brieftasche besitzen.</translation>
+ </message>
+ <message>
<source>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source>
<translation>Lesen von %s fehlgeschlagen! Alle Schlüssel wurden korrekt gelesen, Transaktionsdaten bzw. Adressbucheinträge fehlen aber möglicherweise oder sind inkorrekt.</translation>
</message>
@@ -3070,8 +3094,16 @@
<translation>Befehl ausführen wenn sich eine Wallet-Transaktion verändert (%s im Befehl wird durch die Transaktions-ID ersetzt)</translation>
</message>
<message>
+ <source>Extra transactions to keep in memory for compact block reconstructions (default: %u)</source>
+ <translation>Zusätzliche Transaktionen für kompakten Block-Nachbau im Speicher vorhalten (default: %u)</translation>
+ </message>
+ <message>
+ <source>If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)</source>
+ <translation>Sofern dieser Block Bestandteil der Blockchain ist, nehme an, dass er und seine Vorgänger gültig sind und überspringe ggf. dessen Skriptverifikation (0 um alle zu verifizieren, default: %s, testnet: %s)</translation>
+ </message>
+ <message>
<source>Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)</source>
- <translation>Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)</translation>
+ <translation>Maximal zulässige mediane Peer-Zeit-Offset-Einstellung. Lokale Perspektive der Zeit kann von Peers vorwärts oder rückwärts um diesen Betrag beeinflusst werden. (Voreinstellung: %u Sekunden)</translation>
</message>
<message>
<source>Maximum total fees (in %s) to use in a single wallet transaction or raw transaction; setting this too low may abort large transactions (default: %s)</source>
@@ -3086,6 +3118,14 @@
<translation>Wenn sie %s nützlich finden, sind Helfer sehr gern gesehen. Besuchen Sie %s um mehr über das Softwareprojekt zu erfahren.</translation>
</message>
<message>
+ <source>Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, &gt;%u = automatically prune block files to stay under the specified target size in MiB)</source>
+ <translation>Speicherplatzanforderung durch Kürzen (Pruning) alter Blöcke reduzieren. Dies erlaubt das Aufrufen des sogenannten Pruneblockchain RPC zum Löschen spezifischer Blöcke und und aktiviert das automatische Pruning alter Blöcke, sofern eine Zielgröße in MIB angegeben wird. Dieser Modus ist nicht mit -txindex und -resacan kompatibel. Warnung: Das Rücksetzen dieser Einstellung erfordert das erneute Herunterladen der gesamten Blockchain. (Standard: 0 = deaktiviert das Pruning, 1 = erlaubt manuelles Pruning via RPC, &gt;%u = automatisches Pruning der Blockdateien, um angegebene Maximalgröße nicht zu überschreiten)</translation>
+ </message>
+ <message>
+ <source>Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)</source>
+ <translation>Niedrigste Gebühr (in %s/kB) für Transaktionen einstellen, die bei der Blockerzeugung berücksichtigt werden sollen. (default: %s)</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>
@@ -3106,6 +3146,14 @@
<translation>UPnP verwenden, um eine Portweiterleitung einzurichten (Standard: 1, wenn abgehört wird und -proxy nicht gesetzt ist)</translation>
</message>
<message>
+ <source>Username and hashed password for JSON-RPC connections. The field &lt;userpw&gt; comes in the format: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=&lt;USERNAME&gt;/rpcpassword=&lt;PASSWORD&gt; pair of arguments. This option can be specified multiple times</source>
+ <translation>Benutzername und gehashtes Passwort für JSON-RPC Verbindungen. Das Feld &lt;userpw&gt; kommt im Format: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. Ein kanonisches Pythonskript ist in share/rpcuser inbegriffen. Der client benutzt wie gehabt, die rpcuser/rpcpassword Parameter. Diese Option kann mehrere Male spezifiziert werden</translation>
+ </message>
+ <message>
+ <source>Wallet will not create transactions that violate mempool chain limits (default: %u)</source>
+ <translation>Das Wallet erzeugt keine Transaktionen, die das Mempool Chain Limit überschreiten (Standardeinstellung: %u)</translation>
+ </message>
+ <message>
<source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
<translation>Warnung: Das Netzwerk scheint nicht vollständig übereinzustimmen! Einige Miner scheinen Probleme zu haben.</translation>
</message>
@@ -3146,6 +3194,10 @@
<translation>Kann Adresse in -%s nicht auflösen: '%s'</translation>
</message>
<message>
+ <source>Chain selection options:</source>
+ <translation>Chain Auswahloptionen:</translation>
+ </message>
+ <message>
<source>Change index out of range</source>
<translation>Position des Wechselgelds außerhalb des Bereichs</translation>
</message>
@@ -3214,6 +3266,10 @@
<translation>Fehler beim Laden von %s: Das Wallet benötigt eine neuere Version von %s</translation>
</message>
<message>
+ <source>Error loading %s: You can't disable HD on a already existing HD wallet</source>
+ <translation>Fehler beim Laden von %s: Sie können die hierarchisch deterministische Schlüsselgeneration (HD) für eine bereits existierende HD-Brieftasche nicht deaktivieren</translation>
+ </message>
+ <message>
<source>Error loading block database</source>
<translation>Fehler beim Laden der Blockdatenbank</translation>
</message>
@@ -3295,7 +3351,7 @@
</message>
<message>
<source>Rebuild chain state from the currently indexed blocks</source>
- <translation>Blockkettenindex aus aktuellen Dateien blk000??.dat wiederaufbauen</translation>
+ <translation>Blockkettenzustand aus aktuelle indizierten Blöcken wiederaufbauen</translation>
</message>
<message>
<source>Rewinding blocks...</source>
@@ -3427,7 +3483,7 @@
</message>
<message>
<source>Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start</source>
- <translation>Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start</translation>
+ <translation>Verwende hierarchisch deterministische Schlüsselgenerierung (HD) nach BIP32. Funktioniert nur bei der Erstellung (erster Start) von einer Brieftasche.</translation>
</message>
<message>
<source>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</source>
@@ -3638,6 +3694,10 @@
<translation>Adressen von Gegenstellen via DNS-Namensauflösung finden, falls zu wenige Adressen verfügbar sind (Standard: 1, außer bei -connect/-noconnect)</translation>
</message>
<message>
+ <source>Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(1) (default: %d)</source>
+ <translation>Setzt die Serialisierung von Rohtransaktionen oder Block Hex-Daten auf non-verbose mode, nicht-Segwit(0) oder Segwit(1) (default: %d)</translation>
+ </message>
+ <message>
<source>Support filtering of blocks and transaction with bloom filters (default: %u)</source>
<translation>Unterstütze Blöcke und Transaktionen mit Bloomfiltern zu filtern (default: %u)</translation>
</message>
@@ -3675,7 +3735,7 @@
</message>
<message>
<source>%s is set very high!</source>
- <translation>%s wurde sehr hoch Eingestellt!</translation>
+ <translation>%s wurde sehr hoch eingestellt!</translation>
</message>
<message>
<source>(default: %s)</source>
@@ -3698,6 +3758,10 @@
<translation>Ungültige Adresse in -proxy: '%s'</translation>
</message>
<message>
+ <source>Keypool ran out, please call keypoolrefill first</source>
+ <translation>Der Keypool ist erschöpft. Bitte rufen Sie zunächst keypoolrefill auf.</translation>
+ </message>
+ <message>
<source>Listen for JSON-RPC connections on &lt;port&gt; (default: %u or testnet: %u)</source>
<translation>&lt;port&gt; nach JSON-RPC-Verbindungen abhören (Standard: %u oder Testnetz: %u)</translation>
</message>
@@ -3766,6 +3830,14 @@
<translation>Unbestätigtes Wechselgeld darf beim Senden von Transaktionen ausgegeben werden (Standard: %u)</translation>
</message>
<message>
+ <source>Starting network threads...</source>
+ <translation>Netzwerk-Threads werden gestartet...</translation>
+ </message>
+ <message>
+ <source>The wallet will avoid paying less than the minimum relay fee.</source>
+ <translation>Das Wallet verhindert Zahlungen, die die Mindesttransaktionsgebühr nicht berücksichtigen.</translation>
+ </message>
+ <message>
<source>This is the minimum transaction fee you pay on every transaction.</source>
<translation>Dies ist die minimale Gebühr die beim Senden einer Transaktion fällig wird.</translation>
</message>
@@ -3782,6 +3854,14 @@
<translation>Transaktionsbeträge dürfen nicht negativ sein.</translation>
</message>
<message>
+ <source>Transaction has too long of a mempool chain</source>
+ <translation>Die Speicherpoolkette der Transaktion ist zu lang.</translation>
+ </message>
+ <message>
+ <source>Transaction must have at least one recipient</source>
+ <translation>Die Transaktion muss mindestens einen Empfänger enthalten.</translation>
+ </message>
+ <message>
<source>Unknown network specified in -onlynet: '%s'</source>
<translation>Unbekannter Netztyp in -onlynet angegeben: '%s'</translation>
</message>
diff --git a/src/qt/locale/bitcoin_el_GR.ts b/src/qt/locale/bitcoin_el_GR.ts
index b1caab06b1..2bbc1546a5 100644
--- a/src/qt/locale/bitcoin_el_GR.ts
+++ b/src/qt/locale/bitcoin_el_GR.ts
@@ -41,10 +41,66 @@
<source>&amp;Delete</source>
<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>C&amp;hoose</source>
+ <translation>Ε&amp;πιλογή</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Διευθύνσεις αποστολής</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Διευθύνσεις λήψης</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Αντιγραφή Διεύθυνσης</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Αντιγραφή&amp;Ετικέτα</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Διόρθωση</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Εξαγωγή Λίστας Διεύθυνσεων</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Αρχείο οριοθετημένο με κόμματα (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Αποτυχία Εξαγωγής</translation>
+ </message>
</context>
<context>
<name>AddressTableModel</name>
- </context>
+ <message>
+ <source>Label</source>
+ <translation>Ετικέτα</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Διεύθυνση</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(χωρίς ετικέτα)</translation>
+ </message>
+</context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -63,6 +119,22 @@
<source>Repeat new passphrase</source>
<translation>Επανέλαβε τον νέο κωδικό πρόσβασης</translation>
</message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Κρυπτογράφηση πορτοφολιού</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Ξεκλειδωσε το πορτοφολι</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Αλλάξτε Φράση Πρόσβασης</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Το Ξεκλείδωμα του Πορτοφολιού Απέτυχε</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
@@ -246,10 +318,6 @@
<translation>&amp;Επιλογές γραμμής εντολών</translation>
</message>
<message>
- <source>No block source available...</source>
- <translation>Η πηγή του μπλοκ δεν ειναι διαθέσιμη... </translation>
- </message>
- <message>
<source>%1 behind</source>
<translation>%1 πίσω</translation>
</message>
@@ -398,6 +466,26 @@
<source>Confirmed</source>
<translation>Επικυρωμένες</translation>
</message>
+ <message>
+ <source>Copy address</source>
+ <translation>Αντιγραφή διεύθυνσης</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Αντιγραφή ετικέτας</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Αντιγραφή ποσού</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Αντιγραφή ταυτότητας συναλλαγής</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(χωρίς ετικέτα)</translation>
+ </message>
</context>
<context>
<name>EditAddressDialog</name>
@@ -421,6 +509,18 @@
<source>&amp;Address</source>
<translation>&amp;Διεύθυνση</translation>
</message>
+ <message>
+ <source>New receiving address</source>
+ <translation>Νέα Διεύθυνση Λήψης</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Νέα Διεύθυνση Αποστολής</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Διόρθωση Διεύθυνσης Λήψης</translation>
+ </message>
</context>
<context>
<name>FreespaceChecker</name>
@@ -1068,7 +1168,15 @@
<source>Remove</source>
<translation>Αφαίρεση</translation>
</message>
- </context>
+ <message>
+ <source>Copy label</source>
+ <translation>Αντιγραφή ετικέτας</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Αντιγραφή ποσού</translation>
+ </message>
+</context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -1087,9 +1195,29 @@
<source>&amp;Save Image...</source>
<translation>&amp;Αποθήκευση εικόνας...</translation>
</message>
+ <message>
+ <source>Address</source>
+ <translation>Διεύθυνση</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Ετικέτα</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Ημερομήνια</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Ετικέτα</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(χωρίς ετικέτα)</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -1213,7 +1341,15 @@
<source>S&amp;end</source>
<translation>Αποστολη</translation>
</message>
- </context>
+ <message>
+ <source>Copy amount</source>
+ <translation>Αντιγραφή ποσού</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(χωρίς ετικέτα)</translation>
+ </message>
+</context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -1378,6 +1514,70 @@
</context>
<context>
<name>TransactionDesc</name>
+ <message>
+ <source>Open until %1</source>
+ <translation>Ανοιχτό μέχρι %1</translation>
+ </message>
+ <message>
+ <source>%1/offline</source>
+ <translation>%1/αποσυνδεδεμένο</translation>
+ </message>
+ <message>
+ <source>0/unconfirmed, %1</source>
+ <translation>0/ανεπιβεβαίωτο, %1</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Ημερομηνία</translation>
+ </message>
+ <message>
+ <source>Source</source>
+ <translation>Πηγή</translation>
+ </message>
+ <message>
+ <source>Generated</source>
+ <translation>Παράχθηκε</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>Από</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>Άγνωστο</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation>Προς</translation>
+ </message>
+ <message>
+ <source>own address</source>
+ <translation>δική σας διεύθυνση</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>παρακολούθηση-μόνο</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>ετικέτα</translation>
+ </message>
+ <message>
+ <source>Credit</source>
+ <translation>Πίστωση</translation>
+ </message>
+ <message>
+ <source>not accepted</source>
+ <translation>μη έγκυρο</translation>
+ </message>
+ <message>
+ <source>Total credit</source>
+ <translation>Συνολική πίστωση</translation>
+ </message>
+ <message>
+ <source>Transaction fee</source>
+ <translation>Κόστος συναλλαγής</translation>
+ </message>
</context>
<context>
<name>TransactionDescDialog</name>
@@ -1388,9 +1588,73 @@
</context>
<context>
<name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Ημερομήνια</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Ετικέτα</translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>Ανοιχτό μέχρι %1</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>παρακολούθηση-μόνο</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(χωρίς ετικέτα)</translation>
+ </message>
</context>
<context>
<name>TransactionView</name>
+ <message>
+ <source>Copy address</source>
+ <translation>Αντιγραφή διεύθυνσης</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Αντιγραφή ετικέτας</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Αντιγραφή ποσού</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Αντιγραφή ταυτότητας συναλλαγής</translation>
+ </message>
+ <message>
+ <source>Copy raw transaction</source>
+ <translation>Αντιγραφή ανεπεξέργαστης συναλλαγής</translation>
+ </message>
+ <message>
+ <source>Edit label</source>
+ <translation>Επεξεργασία ετικέτας</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Αρχείο οριοθετημένο με κόμματα (*.csv)</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Ημερομήνια</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Ετικέτα</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Διεύθυνση</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Αποτυχία Εξαγωγής</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts
index 60dcc9f701..821be8987e 100644
--- a/src/qt/locale/bitcoin_en.ts
+++ b/src/qt/locale/bitcoin_en.ts
@@ -127,7 +127,7 @@
<context>
<name>AddressTableModel</name>
<message>
- <location filename="../addresstablemodel.cpp" line="+170"/>
+ <location filename="../addresstablemodel.cpp" line="+169"/>
<source>Label</source>
<translation type="unfinished"></translation>
</message>
@@ -299,17 +299,17 @@
<context>
<name>BitcoinGUI</name>
<message>
- <location filename="../bitcoingui.cpp" line="+356"/>
+ <location filename="../bitcoingui.cpp" line="+357"/>
<source>Sign &amp;message...</source>
<translation>Sign &amp;message...</translation>
</message>
<message>
- <location line="+417"/>
+ <location line="+429"/>
<source>Synchronizing with network...</source>
<translation>Synchronizing with network...</translation>
</message>
<message>
- <location line="-495"/>
+ <location line="-507"/>
<source>&amp;Overview</source>
<translation>&amp;Overview</translation>
</message>
@@ -404,7 +404,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+357"/>
+ <location line="+359"/>
<source>Click to disable network activity.</source>
<translation type="unfinished"></translation>
</message>
@@ -419,12 +419,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+53"/>
+ <location line="+27"/>
+ <source>Syncing Headers (%1%)...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+37"/>
<source>Reindexing blocks on disk...</source>
<translation>Reindexing blocks on disk...</translation>
</message>
<message>
- <location line="-497"/>
+ <location line="-510"/>
<source>Send coins to a Bitcoin address</source>
<translation>Send coins to a Bitcoin address</translation>
</message>
@@ -454,12 +459,12 @@
<translation>&amp;Verify message...</translation>
</message>
<message>
- <location line="+504"/>
+ <location line="+516"/>
<source>Bitcoin</source>
<translation>Bitcoin</translation>
</message>
<message>
- <location line="-729"/>
+ <location line="-741"/>
<source>Wallet</source>
<translation>Wallet</translation>
</message>
@@ -544,7 +549,7 @@
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
- <location line="+354"/>
+ <location line="+356"/>
<source>%n active connection(s) to Bitcoin network</source>
<translation>
<numerusform>%n active connection to Bitcoin network</numerusform>
@@ -552,7 +557,7 @@
</translation>
</message>
<message>
- <location line="+49"/>
+ <location line="+60"/>
<source>Indexing blocks on disk...</source>
<translation type="unfinished"></translation>
</message>
@@ -561,13 +566,8 @@
<source>Processing blocks on disk...</source>
<translation type="unfinished"></translation>
</message>
- <message>
- <location line="+11"/>
- <source>No block source available...</source>
- <translation>No block source available...</translation>
- </message>
<message numerus="yes">
- <location line="+9"/>
+ <location line="+19"/>
<source>Processed %n block(s) of transaction history.</source>
<translation>
<numerusform>Processed %n block of transaction history.</numerusform>
@@ -610,17 +610,22 @@
<translation>Up to date</translation>
</message>
<message>
- <location line="-428"/>
+ <location line="-440"/>
<source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+197"/>
+ <location line="+199"/>
<source>%1 client</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+255"/>
+ <location line="+227"/>
+ <source>Connecting to peers...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+38"/>
<source>Catching up...</source>
<translation>Catching up...</translation>
</message>
@@ -685,7 +690,7 @@
<translation>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</translation>
</message>
<message>
- <location filename="../bitcoin.cpp" line="+518"/>
+ <location filename="../bitcoin.cpp" line="+534"/>
<source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
<translation type="unfinished"></translation>
</message>
@@ -778,7 +783,7 @@
<translation type="unfinished">Confirmed</translation>
</message>
<message>
- <location filename="../coincontroldialog.cpp" line="+55"/>
+ <location filename="../coincontroldialog.cpp" line="+54"/>
<source>Copy address</source>
<translation type="unfinished"></translation>
</message>
@@ -844,7 +849,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+183"/>
+ <location line="+155"/>
<source>yes</source>
<translation type="unfinished"></translation>
</message>
@@ -859,7 +864,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+9"/>
+ <location line="+5"/>
<source>Can vary +/- %1 satoshi(s) per input.</source>
<translation type="unfinished"></translation>
</message>
@@ -951,7 +956,7 @@
<context>
<name>FreespaceChecker</name>
<message>
- <location filename="../intro.cpp" line="+78"/>
+ <location filename="../intro.cpp" line="+76"/>
<source>A new data directory will be created.</source>
<translation>A new data directory will be created.</translation>
</message>
@@ -1063,12 +1068,22 @@
<translation type="unfinished"></translation>
</message>
<message>
+ <location line="+157"/>
+ <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
<location line="+10"/>
- <source>%1 will download and store a copy of the Bitcoin block chain. At least %2GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory.</source>
+ <source>This initial synchronisation is very demanding, and may expose hardware problems with your computer that had previously gone unnoticed. Each time you run %1, it will continue downloading where it left off.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+10"/>
+ <source>If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-160"/>
<source>Use the default data directory</source>
<translation>Use the default data directory</translation>
</message>
@@ -1078,7 +1093,32 @@
<translation>Use a custom data directory:</translation>
</message>
<message>
- <location filename="../intro.cpp" line="+89"/>
+ <location filename="../intro.cpp" line="+20"/>
+ <source>Bitcoin</source>
+ <translation type="unfinished">Bitcoin</translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+5"/>
+ <source>Approximately %1 GB of data will be stored in this directory.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+8"/>
+ <source>%1 will download and store a copy of the Bitcoin block chain.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>The wallet will also be stored in this directory.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+70"/>
<source>Error: Specified data directory &quot;%1&quot; cannot be created.</source>
<translation type="unfinished"></translation>
</message>
@@ -1129,7 +1169,7 @@
<message>
<location line="+7"/>
<location line="+26"/>
- <location filename="../modaloverlay.cpp" line="+136"/>
+ <location filename="../modaloverlay.cpp" line="+138"/>
<source>Unknown...</source>
<translation type="unfinished"></translation>
</message>
@@ -1252,7 +1292,14 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+94"/>
+ <location line="-118"/>
+ <location line="+23"/>
+ <location line="+23"/>
+ <source>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+166"/>
<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 type="unfinished"></translation>
</message>
@@ -1273,7 +1320,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+43"/>
+ <location line="+45"/>
+ <source>Open the %1 configuration file from the working directory.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Open Configuration File</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+10"/>
<source>Reset all client options to default.</source>
<translation>Reset all client options to default.</translation>
</message>
@@ -1283,7 +1340,7 @@
<translation>&amp;Reset Options</translation>
</message>
<message>
- <location line="-514"/>
+ <location line="-529"/>
<source>&amp;Network</source>
<translation>&amp;Network</translation>
</message>
@@ -1361,14 +1418,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+13"/>
- <location line="+23"/>
<location line="+23"/>
- <source>Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="-36"/>
<source>IPv4</source>
<translation type="unfinished"></translation>
</message>
@@ -1453,7 +1503,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+612"/>
+ <location line="+646"/>
<source>&amp;OK</source>
<translation>&amp;OK</translation>
</message>
@@ -1463,7 +1513,7 @@
<translation>&amp;Cancel</translation>
</message>
<message>
- <location filename="../optionsdialog.cpp" line="+86"/>
+ <location filename="../optionsdialog.cpp" line="+84"/>
<source>default</source>
<translation>default</translation>
</message>
@@ -1479,22 +1529,42 @@
</message>
<message>
<location line="+1"/>
- <location line="+43"/>
+ <location line="+55"/>
<source>Client restart required to activate changes.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-43"/>
+ <location line="-55"/>
<source>Client will be shut down. Do you want to proceed?</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+47"/>
+ <location line="+15"/>
+ <source>Configuration options</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>The configuration file is used to specify advanced user options which override GUI settings. Additionally, any command-line options will override this configuration file.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+5"/>
+ <source>Error</source>
+ <translation type="unfinished">Error</translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>The configuration file could not be opened.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+38"/>
<source>This change would require a client restart.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+25"/>
+ <location line="+28"/>
<source>The supplied proxy address is invalid.</source>
<translation>The supplied proxy address is invalid.</translation>
</message>
@@ -1750,12 +1820,12 @@
<translation type="unfinished">Amount</translation>
</message>
<message>
- <location filename="../guiutil.cpp" line="+136"/>
+ <location filename="../guiutil.cpp" line="+130"/>
<source>Enter a Bitcoin address (e.g. %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+759"/>
+ <location line="+766"/>
<source>%1 d</source>
<translation type="unfinished"></translation>
</message>
@@ -1845,7 +1915,7 @@
</translation>
</message>
<message>
- <location filename="../bitcoin.cpp" line="+172"/>
+ <location filename="../bitcoin.cpp" line="+178"/>
<source>%1 didn&apos;t yet exit safely...</source>
<translation type="unfinished"></translation>
</message>
@@ -1853,7 +1923,7 @@
<context>
<name>QObject::QObject</name>
<message>
- <location line="-81"/>
+ <location line="-86"/>
<source>Error: Specified data directory &quot;%1&quot; does not exist.</source>
<translation type="unfinished"></translation>
</message>
@@ -2002,7 +2072,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+404"/>
+ <location line="+324"/>
+ <source>&amp;Reset</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+80"/>
<location line="+558"/>
<source>Received</source>
<translation type="unfinished"></translation>
@@ -2025,8 +2100,8 @@
</message>
<message>
<location line="+60"/>
- <location filename="../rpcconsole.cpp" line="+456"/>
- <location line="+719"/>
+ <location filename="../rpcconsole.cpp" line="+467"/>
+ <location line="+728"/>
<source>Select a peer to view detailed information.</source>
<translation type="unfinished"></translation>
</message>
@@ -2152,12 +2227,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+52"/>
- <source>&amp;Clear</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+16"/>
+ <location line="+68"/>
<source>Totals</source>
<translation type="unfinished"></translation>
</message>
@@ -2182,7 +2252,7 @@
<translation>Clear console</translation>
</message>
<message>
- <location filename="../rpcconsole.cpp" line="-214"/>
+ <location filename="../rpcconsole.cpp" line="-223"/>
<source>1 &amp;hour</source>
<translation type="unfinished"></translation>
</message>
@@ -2220,23 +2290,23 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+126"/>
+ <location line="+135"/>
<source>Welcome to the %1 RPC console.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
- <source>Use up and down arrows to navigate history, and &lt;b&gt;Ctrl-L&lt;/b&gt; to clear screen.</source>
- <translation>Use up and down arrows to navigate history, and &lt;b&gt;Ctrl-L&lt;/b&gt; to clear screen.</translation>
- </message>
- <message>
- <location line="+1"/>
+ <location line="+2"/>
<source>Type &lt;b&gt;help&lt;/b&gt; for an overview of available commands.</source>
<translation>Type &lt;b&gt;help&lt;/b&gt; for an overview of available commands.</translation>
</message>
<message>
- <location line="+2"/>
- <source>WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramification of a command.</source>
+ <location line="-1"/>
+ <source>Use up and down arrows to navigate history, and %1 to clear screen.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -2489,7 +2559,7 @@
<context>
<name>RecentRequestsTableModel</name>
<message>
- <location filename="../recentrequeststablemodel.cpp" line="+29"/>
+ <location filename="../recentrequeststablemodel.cpp" line="+28"/>
<source>Date</source>
<translation type="unfinished">Date</translation>
</message>
@@ -2504,7 +2574,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+40"/>
+ <location line="+39"/>
<source>(no label)</source>
<translation type="unfinished"></translation>
</message>
@@ -2528,7 +2598,7 @@
<name>SendCoinsDialog</name>
<message>
<location filename="../forms/sendcoinsdialog.ui" line="+14"/>
- <location filename="../sendcoinsdialog.cpp" line="+553"/>
+ <location filename="../sendcoinsdialog.cpp" line="+586"/>
<source>Send Coins</source>
<translation>Send Coins</translation>
</message>
@@ -2603,7 +2673,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+37"/>
+ <location line="+24"/>
+ <source>Using the fallbackfee can result in sending a transaction that will take several hours or days (or never) to confirm. Consider choosing your fee manually or wait until you have validated the complete chain.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+9"/>
+ <source>Warning: Fee estimation is currently not possible.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+26"/>
<source>collapse fee-settings</source>
<translation type="unfinished"></translation>
</message>
@@ -2614,22 +2694,16 @@
</message>
<message>
<location line="-3"/>
- <location line="+16"/>
<source>If the custom fee is set to 1000 satoshis and the transaction is only 250 bytes, then &quot;per kilobyte&quot; only pays 250 satoshis in fee, while &quot;total at least&quot; pays 1000 satoshis. For transactions bigger than a kilobyte both pay by kilobyte.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-64"/>
+ <location line="-48"/>
<source>Hide</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+67"/>
- <source>total at least</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+30"/>
+ <location line="+84"/>
<location line="+13"/>
<source>Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks. But be aware that this can end up in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source>
<translation type="unfinished"></translation>
@@ -2655,17 +2729,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+89"/>
- <source>normal</source>
+ <location line="+103"/>
+ <source>Request Replace-By-Fee</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+40"/>
- <source>fast</source>
+ <location line="+3"/>
+ <source>Indicates that the sender may wish to replace this transaction with a new one paying higher fees (prior to being confirmed).</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+102"/>
+ <location line="+79"/>
<source>Send to multiple recipients at once</source>
<translation>Send to multiple recipients at once</translation>
</message>
@@ -2680,17 +2754,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-876"/>
+ <location line="-839"/>
<source>Dust:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+691"/>
+ <location line="+700"/>
<source>Confirmation time target:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+188"/>
+ <location line="+142"/>
<source>Clear &amp;All</source>
<translation>Clear &amp;All</translation>
</message>
@@ -2710,7 +2784,7 @@
<translation>S&amp;end</translation>
</message>
<message>
- <location filename="../sendcoinsdialog.cpp" line="-486"/>
+ <location filename="../sendcoinsdialog.cpp" line="-499"/>
<source>Copy quantity</source>
<translation type="unfinished"></translation>
</message>
@@ -2745,7 +2819,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+205"/>
+ <location line="+82"/>
+ <source>%1 (%2 blocks)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+129"/>
<location line="+5"/>
<location line="+5"/>
<location line="+4"/>
@@ -2773,7 +2852,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
+ <location line="+5"/>
+ <source>This transaction signals replaceability (optin-RBF).</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
<source>Confirm send coins</source>
<translation type="unfinished"></translation>
</message>
@@ -2822,21 +2906,13 @@
<source>Payment request expired.</source>
<translation type="unfinished"></translation>
</message>
- <message numerus="yes">
- <location line="+67"/>
- <source>%n block(s)</source>
- <translation>
- <numerusform>%n block</numerusform>
- <numerusform>%n blocks</numerusform>
- </translation>
- </message>
<message>
- <location line="+28"/>
+ <location line="+68"/>
<source>Pay only the required fee of %1</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
- <location line="+25"/>
+ <location line="+42"/>
<source>Estimated to begin confirmation within %n block(s).</source>
<translation>
<numerusform>Estimated to begin confirmation within %n block.</numerusform>
@@ -2844,7 +2920,7 @@
</translation>
</message>
<message>
- <location line="+102"/>
+ <location line="+101"/>
<source>Warning: Invalid Bitcoin address</source>
<translation type="unfinished"></translation>
</message>
@@ -2981,7 +3057,7 @@
<context>
<name>SendConfirmationDialog</name>
<message>
- <location filename="../sendcoinsdialog.cpp" line="+95"/>
+ <location filename="../sendcoinsdialog.cpp" line="+83"/>
<location line="+5"/>
<source>Yes</source>
<translation type="unfinished"></translation>
@@ -3193,7 +3269,7 @@
<context>
<name>TrafficGraphWidget</name>
<message>
- <location filename="../trafficgraphwidget.cpp" line="+79"/>
+ <location filename="../trafficgraphwidget.cpp" line="+80"/>
<source>KB/s</source>
<translation type="unfinished"></translation>
</message>
@@ -3422,7 +3498,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+21"/>
+ <location line="+20"/>
<source>Amount</source>
<translation type="unfinished">Amount</translation>
</message>
@@ -3455,7 +3531,7 @@
<context>
<name>TransactionTableModel</name>
<message>
- <location filename="../transactiontablemodel.cpp" line="+246"/>
+ <location filename="../transactiontablemodel.cpp" line="+248"/>
<source>Date</source>
<translation type="unfinished">Date</translation>
</message>
@@ -3601,7 +3677,7 @@
<context>
<name>TransactionView</name>
<message>
- <location filename="../transactionview.cpp" line="+69"/>
+ <location filename="../transactionview.cpp" line="+70"/>
<location line="+16"/>
<source>All</source>
<translation type="unfinished"></translation>
@@ -3672,12 +3748,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+36"/>
+ <location line="+37"/>
<source>Abandon transaction</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
+ <source>Increase transaction fee</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
<source>Copy address</source>
<translation type="unfinished"></translation>
</message>
@@ -3717,7 +3798,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+186"/>
+ <location line="+193"/>
<source>Export Transaction History</source>
<translation type="unfinished"></translation>
</message>
@@ -3782,7 +3863,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+147"/>
+ <location line="+166"/>
<source>Range:</source>
<translation type="unfinished"></translation>
</message>
@@ -3815,6 +3896,53 @@
<source>Send Coins</source>
<translation type="unfinished">Send Coins</translation>
</message>
+ <message>
+ <location line="+387"/>
+ <location line="+46"/>
+ <location line="+9"/>
+ <source>Fee bump error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-55"/>
+ <source>Increasing transaction fee failed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <source>Do you want to increase the fee?</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <source>Current fee:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>Increase:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>New fee:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>Confirm fee bump</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+22"/>
+ <source>Can&apos;t sign transaction.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+9"/>
+ <source>Could not commit transaction</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>WalletView</name>
@@ -3862,7 +3990,7 @@
<context>
<name>bitcoin-core</name>
<message>
- <location filename="../bitcoinstrings.cpp" line="+311"/>
+ <location filename="../bitcoinstrings.cpp" line="+343"/>
<source>Options:</source>
<translation>Options:</translation>
</message>
@@ -3872,42 +4000,32 @@
<translation>Specify data directory</translation>
</message>
<message>
- <location line="-90"/>
+ <location line="-95"/>
<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="+93"/>
+ <location line="+98"/>
<source>Specify your own public address</source>
<translation>Specify your own public address</translation>
</message>
<message>
- <location line="-108"/>
+ <location line="-114"/>
<source>Accept command line and JSON-RPC commands</source>
<translation>Accept command line and JSON-RPC commands</translation>
</message>
<message>
- <location line="-214"/>
- <source>Accept connections from outside (default: 1 if no -proxy or -connect/-noconnect)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+22"/>
- <source>Connect only to the specified node(s); -noconnect or -connect=0 alone to disable automatic connections</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+12"/>
+ <location line="-207"/>
<source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+34"/>
+ <location line="+44"/>
<source>If &lt;category&gt; is not supplied or if &lt;category&gt; = 1, output all debugging information.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+32"/>
+ <location line="+36"/>
<source>Prune configured below the minimum of %d MiB. Please use a higher number.</source>
<translation type="unfinished"></translation>
</message>
@@ -3922,7 +4040,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+132"/>
+ <location line="+150"/>
<source>Error: A fatal internal error occurred, see debug.log for details</source>
<translation type="unfinished"></translation>
</message>
@@ -3932,12 +4050,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+40"/>
+ <location line="+41"/>
<source>Pruning blockstore...</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+10"/>
+ <location line="+11"/>
<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>
@@ -3947,7 +4065,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-353"/>
+ <location line="-386"/>
<source>Bitcoin Core</source>
<translation type="unfinished">Bitcoin Core</translation>
</message>
@@ -3962,7 +4080,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
+ <location line="+3"/>
<source>Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)</source>
<translation type="unfinished"></translation>
</message>
@@ -3972,7 +4090,7 @@
<translation>Bind to given address and always listen on it. Use [host]:port notation for IPv6</translation>
</message>
<message>
- <location line="+10"/>
+ <location line="+12"/>
<source>Cannot obtain a lock on data directory %s. %s is probably already running.</source>
<translation type="unfinished"></translation>
</message>
@@ -3982,22 +4100,32 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+13"/>
- <source>Error loading %s: You can&apos;t enable HD on a already existing non-HD wallet</source>
+ <location line="+18"/>
+ <source>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
- <source>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source>
+ <location line="+5"/>
+ <source>Exclude debugging information for a category. Can be used in conjunction with -debug=1 to output debug logs for all categories except one or more specified categories.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+8"/>
+ <location line="+7"/>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
<translation>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</translation>
</message>
<message>
- <location line="+29"/>
+ <location line="+6"/>
+ <source>Extra transactions to keep in memory for compact block reconstructions (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+20"/>
+ <source>If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+10"/>
<source>Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)</source>
<translation type="unfinished"></translation>
</message>
@@ -4017,7 +4145,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+14"/>
+ <location line="+8"/>
+ <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect used)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
<source>Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, &gt;%u = automatically prune block files to stay under the specified target size in MiB)</source>
<translation type="unfinished"></translation>
</message>
@@ -4027,7 +4160,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+5"/>
+ <location line="+3"/>
<source>Set the number of script verification threads (%u to %d, 0 = auto, &lt;0 = leave that many cores free, default: %d)</source>
<translation type="unfinished"></translation>
</message>
@@ -4037,12 +4170,22 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+7"/>
+ <location line="+12"/>
<source>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source>
<translation type="unfinished"></translation>
</message>
<message>
+ <location line="+3"/>
+ <source>This is the transaction fee you may discard if change is smaller than dust at this level</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
<location line="+15"/>
+ <source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
<source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source>
<translation type="unfinished"></translation>
</message>
@@ -4072,17 +4215,32 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+12"/>
+ <location line="+3"/>
+ <source>Whether to save the mempool on shutdown and load on restart (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+11"/>
<source>You need to rebuild the database using -reindex-chainstate to change -txindex</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
+ <source>%d of last 100 blocks have unexpected version</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>%s corrupt, salvage failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+4"/>
+ <source>(press q to shutdown and continue later)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>-maxmempool must be at least %d MB</source>
<translation type="unfinished"></translation>
</message>
@@ -4092,7 +4250,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
+ <location line="+2"/>
+ <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+5"/>
<source>Append comment to the user agent string</source>
<translation type="unfinished"></translation>
</message>
@@ -4202,22 +4365,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
- <source>Error loading %s: You can&apos;t disable HD on a already existing HD wallet</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+1"/>
+ <location line="+2"/>
<source>Error loading block database</source>
<translation>Error loading block database</translation>
</message>
<message>
- <location line="+1"/>
+ <location line="+4"/>
<source>Error opening block database</source>
<translation>Error opening block database</translation>
</message>
<message>
- <location line="+4"/>
+ <location line="+5"/>
<source>Error: Disk space is low!</source>
<translation>Error: Disk space is low!</translation>
</message>
@@ -4242,13 +4400,13 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
- <source>Invalid -onion address: &apos;%s&apos;</source>
+ <location line="+4"/>
+ <source>Invalid amount for -%s=&lt;amount&gt;: &apos;%s&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
- <source>Invalid amount for -%s=&lt;amount&gt;: &apos;%s&apos;</source>
+ <location line="+1"/>
+ <source>Invalid amount for -discardfee=&lt;amount&gt;: &apos;%s&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -4262,7 +4420,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+5"/>
+ <location line="+4"/>
+ <source>Loading P2P addresses...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>Loading banlist...</source>
<translation type="unfinished"></translation>
</message>
@@ -4312,12 +4475,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
+ <location line="+4"/>
+ <source>Replaying blocks...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
<source>Rewinding blocks...</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+5"/>
+ <location line="+4"/>
<source>Set database cache size in megabytes (%d to %d, default: %d)</source>
<translation type="unfinished"></translation>
</message>
@@ -4337,7 +4505,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+16"/>
+ <location line="+11"/>
+ <source>Transaction fee and change calculation failed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
<source>Unable to bind to %s on this computer. %s is probably already running.</source>
<translation type="unfinished"></translation>
</message>
@@ -4357,7 +4530,17 @@
<translation type="unfinished"></translation>
</message>
<message>
+ <location line="+1"/>
+ <source>Unsupported logging category %s=%s.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
<location line="+2"/>
+ <source>Upgrading UTXO database</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>Use UPnP to map the listening port (default: %u)</source>
<translation type="unfinished"></translation>
</message>
@@ -4377,12 +4560,7 @@
<translation>Verifying blocks...</translation>
</message>
<message>
- <location line="+1"/>
- <source>Verifying wallet...</source>
- <translation>Verifying wallet...</translation>
- </message>
- <message>
- <location line="+1"/>
+ <location line="+2"/>
<source>Wallet %s resides outside data directory %s</source>
<translation>Wallet %s resides outside data directory %s</translation>
</message>
@@ -4402,7 +4580,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-351"/>
+ <location line="-389"/>
<source>Allow JSON-RPC connections from specified source. Valid for &lt;ip&gt; 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</source>
<translation type="unfinished"></translation>
</message>
@@ -4412,12 +4590,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
- <source>Bind to given address to listen for JSON-RPC connections. Use [host]:port notation for IPv6. This option can be specified multiple times (default: bind to all interfaces)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+9"/>
+ <location line="+14"/>
<source>Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)</source>
<translation type="unfinished"></translation>
</message>
@@ -4427,17 +4600,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+15"/>
+ <location line="+18"/>
<source>Error: Listening for incoming connections failed (listen returned error %s)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
+ <location line="+6"/>
<source>Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)</source>
<translation>Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)</translation>
</message>
<message>
- <location line="+9"/>
+ <location line="+12"/>
<source>Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)</source>
<translation type="unfinished"></translation>
</message>
@@ -4447,7 +4620,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+7"/>
<source>Invalid amount for -maxtxfee=&lt;amount&gt;: &apos;%s&apos; (must be at least the minrelay fee of %s to prevent stuck transactions)</source>
<translation type="unfinished"></translation>
</message>
@@ -4462,22 +4635,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+18"/>
- <source>Set maximum size of high-priority/low-fee transactions in bytes (default: %d)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+15"/>
+ <location line="+36"/>
<source>The transaction amount is too small to send after the fee has been deducted</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+28"/>
+ <location line="+34"/>
<source>Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+31"/>
+ <location line="+33"/>
<source>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</source>
<translation type="unfinished"></translation>
</message>
@@ -4487,12 +4655,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+8"/>
+ <location line="+9"/>
<source>(default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+4"/>
+ <location line="+6"/>
<source>Accept public REST requests (default: %u)</source>
<translation type="unfinished"></translation>
</message>
@@ -4507,11 +4675,21 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+22"/>
+ <location line="+19"/>
+ <source>Error loading %s: You can&apos;t disable HD on an already existing HD wallet</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
<source>Error reading from database, shutting down.</source>
<translation type="unfinished"></translation>
</message>
<message>
+ <location line="+1"/>
+ <source>Error upgrading chainstate database</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
<location line="+8"/>
<source>Imports blocks from external blk000??.dat file on startup</source>
<translation type="unfinished"></translation>
@@ -4522,7 +4700,17 @@
<translation>Information</translation>
</message>
<message>
- <location line="+7"/>
+ <location line="+3"/>
+ <source>Invalid -onion address or hostname: &apos;%s&apos;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Invalid -proxy address or hostname: &apos;%s&apos;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
<source>Invalid amount for -paytxfee=&lt;amount&gt;: &apos;%s&apos; (must be at least %s)</source>
<translation type="unfinished"></translation>
</message>
@@ -4557,7 +4745,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+4"/>
<source>Rescan the block chain for missing wallet transactions on startup</source>
<translation type="unfinished"></translation>
</message>
@@ -4567,11 +4755,6 @@
<translation>Send trace/debug info to console instead of debug.log file</translation>
</message>
<message>
- <location line="+1"/>
- <source>Send transactions as zero-fee transactions if possible (default: %u)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
<location line="+7"/>
<source>Show all debugging options (usage: --help -help-debug)</source>
<translation type="unfinished"></translation>
@@ -4612,7 +4795,7 @@
<translation>Transaction amount too small</translation>
</message>
<message>
- <location line="+4"/>
+ <location line="+5"/>
<source>Transaction too large for fee policy</source>
<translation type="unfinished"></translation>
</message>
@@ -4627,17 +4810,22 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+7"/>
+ <location line="+8"/>
<source>Upgrade wallet to latest format on startup</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+4"/>
+ <location line="+5"/>
<source>Username for JSON-RPC connections</source>
<translation>Username for JSON-RPC connections</translation>
</message>
<message>
- <location line="+7"/>
+ <location line="+2"/>
+ <source>Verifying wallet(s)...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+5"/>
<source>Warning</source>
<translation>Warning</translation>
</message>
@@ -4662,27 +4850,22 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-73"/>
+ <location line="-76"/>
<source>Password for JSON-RPC connections</source>
<translation>Password for JSON-RPC connections</translation>
</message>
<message>
- <location line="-235"/>
+ <location line="-261"/>
<source>Execute command when the best block changes (%s in cmd is replaced by block hash)</source>
<translation>Execute command when the best block changes (%s in cmd is replaced by block hash)</translation>
</message>
<message>
- <location line="+163"/>
+ <location line="+184"/>
<source>Allow DNS lookups for -addnode, -seednode and -connect</source>
<translation>Allow DNS lookups for -addnode, -seednode and -connect</translation>
</message>
<message>
- <location line="+58"/>
- <source>Loading addresses...</source>
- <translation>Loading addresses...</translation>
- </message>
- <message>
- <location line="-284"/>
+ <location line="-253"/>
<source>(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)</source>
<translation type="unfinished"></translation>
</message>
@@ -4692,7 +4875,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+43"/>
+ <location line="+19"/>
+ <source>Bind to given address to listen for JSON-RPC connections. This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost, or if -rpcallowip has been specified, 0.0.0.0 and :: i.e., all addresses)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+8"/>
+ <source>Connect only to the specified node(s); -connect=0 disables automatic connections</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+15"/>
<source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
<translation type="unfinished"></translation>
</message>
@@ -4702,7 +4895,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+21"/>
+ <location line="+2"/>
+ <source>Error loading %s: You can&apos;t enable HD on an already existing non-HD wallet</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Error loading wallet %s. -wallet parameter must only specify a filename (not a path).</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+27"/>
<source>Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)</source>
<translation type="unfinished"></translation>
</message>
@@ -4717,7 +4920,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+11"/>
+ <location line="+15"/>
<source>Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)</source>
<translation type="unfinished"></translation>
</message>
@@ -4732,12 +4935,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+13"/>
- <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect/-noconnect)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+26"/>
+ <location line="+37"/>
<source>Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(1) (default: %d)</source>
<translation type="unfinished"></translation>
</message>
@@ -4747,7 +4945,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+12"/>
+ <location line="+7"/>
+ <source>The fee rate (in %s/kB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). Note: An output is discarded if it is dust at this rate, but we will always discard up to the dust relay fee and a discard fee above that is limited by the fee estimate for the longest target</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+13"/>
<source>This is the transaction fee you may pay when fee estimates are not available.</source>
<translation type="unfinished"></translation>
</message>
@@ -4767,7 +4970,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
+ <location line="+9"/>
<source>Unsupported argument -socks found. Setting SOCKS version isn&apos;t possible anymore, only SOCKS5 proxies are supported.</source>
<translation type="unfinished"></translation>
</message>
@@ -4792,12 +4995,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+7"/>
+ <location line="+9"/>
<source>Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR notated network (e.g. 1.2.3.0/24). Can be specified multiple times.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+12"/>
+ <location line="+13"/>
<source>%s is set very high!</source>
<translation type="unfinished"></translation>
</message>
@@ -4807,12 +5010,27 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+8"/>
+ <location line="+10"/>
<source>Always query for peer addresses via DNS lookup (default: %u)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+38"/>
+ <location line="+31"/>
+ <source>Error loading wallet %s. -wallet filename must be a regular file.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Error loading wallet %s. Duplicate -wallet filename specified.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Error loading wallet %s. Invalid characters in -wallet filename.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+9"/>
<source>How many blocks to check at startup (default: %u, 0 = all)</source>
<translation type="unfinished"></translation>
</message>
@@ -4822,12 +5040,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
- <source>Invalid -proxy address: &apos;%s&apos;</source>
- <translation>Invalid -proxy address: &apos;%s&apos;</translation>
- </message>
- <message>
- <location line="+7"/>
+ <location line="+14"/>
<source>Keypool ran out, please call keypoolrefill first</source>
<translation type="unfinished"></translation>
</message>
@@ -4947,7 +5160,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
+ <location line="+2"/>
<source>Transaction has too long of a mempool chain</source>
<translation type="unfinished"></translation>
</message>
@@ -4962,27 +5175,27 @@
<translation>Unknown network specified in -onlynet: &apos;%s&apos;</translation>
</message>
<message>
- <location line="-80"/>
+ <location line="-82"/>
<source>Insufficient funds</source>
<translation>Insufficient funds</translation>
</message>
<message>
- <location line="+14"/>
+ <location line="+15"/>
<source>Loading block index...</source>
<translation>Loading block index...</translation>
</message>
<message>
- <location line="-61"/>
+ <location line="-66"/>
<source>Add a node to connect to and attempt to keep the connection open</source>
<translation>Add a node to connect to and attempt to keep the connection open</translation>
</message>
<message>
- <location line="+62"/>
+ <location line="+67"/>
<source>Loading wallet...</source>
<translation>Loading wallet...</translation>
</message>
<message>
- <location line="-55"/>
+ <location line="-60"/>
<source>Cannot downgrade wallet</source>
<translation>Cannot downgrade wallet</translation>
</message>
@@ -4992,17 +5205,17 @@
<translation>Cannot write default address</translation>
</message>
<message>
- <location line="+78"/>
+ <location line="+84"/>
<source>Rescanning...</source>
<translation>Rescanning...</translation>
</message>
<message>
- <location line="-67"/>
+ <location line="-73"/>
<source>Done loading</source>
<translation>Done loading</translation>
</message>
<message>
- <location line="+15"/>
+ <location line="+19"/>
<source>Error</source>
<translation>Error</translation>
</message>
diff --git a/src/qt/locale/bitcoin_en_GB.ts b/src/qt/locale/bitcoin_en_GB.ts
index 1676f67979..8af5db3e64 100644
--- a/src/qt/locale/bitcoin_en_GB.ts
+++ b/src/qt/locale/bitcoin_en_GB.ts
@@ -333,10 +333,6 @@
<source>Processing blocks on disk...</source>
<translation>Processing blocks on disk...</translation>
</message>
- <message>
- <source>No block source available...</source>
- <translation>No block source available...</translation>
- </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation><numerusform>Processed %n block of transaction history.</numerusform><numerusform>Processed %n blocks of transaction history.</numerusform></translation>
@@ -1874,10 +1870,6 @@
<translation>Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)</translation>
</message>
<message>
- <source>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, &gt;%u = target size in MiB to use for block files)</source>
- <translation>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, &gt;%u = target size in MiB to use for block files)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_eo.ts b/src/qt/locale/bitcoin_eo.ts
index 2337c2bd29..16c584c4b1 100644
--- a/src/qt/locale/bitcoin_eo.ts
+++ b/src/qt/locale/bitcoin_eo.ts
@@ -41,10 +41,78 @@
<source>&amp;Delete</source>
<translation>&amp;Forigi</translation>
</message>
- </context>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Elekti la adreson por sendi monerojn</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Elekti la adreson ricevi monerojn kun</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>&amp;Elekti</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Sendaj adresoj</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Ricevaj adresoj</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>Jen viaj Bitmon-adresoj por sendi pagojn. Zorge kontrolu la sumon kaj la alsendan adreson antaŭ ol sendi.</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>Jen viaj bitmonaj adresoj por ricevi pagojn. Estas konsilinde uzi apartan ricevan adreson por ĉiu transakcio.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Kopii Adreson</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Kopii &amp;Etikedon</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Redakti</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Eksporti Adresliston</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Perkome disigita dosiero (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>ekspotado malsukcesinta</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Okazis eraron dum konservo de adreslisto al %1. Bonvolu provi denove.</translation>
+ </message>
+</context>
<context>
<name>AddressTableModel</name>
- </context>
+ <message>
+ <source>Label</source>
+ <translation>Etikedo</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adreso</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(neniu etikedo)</translation>
+ </message>
+</context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -242,10 +310,6 @@
<translation>&amp;Komandliniaj agordaĵoj</translation>
</message>
<message>
- <source>No block source available...</source>
- <translation>Neniu fonto de blokoj trovebla...</translation>
- </message>
- <message>
<source>%1 behind</source>
<translation>mankas %1</translation>
</message>
@@ -390,6 +454,10 @@
<source>Confirmed</source>
<translation>Konfirmita</translation>
</message>
+ <message>
+ <source>(no label)</source>
+ <translation>(neniu etikedo)</translation>
+ </message>
</context>
<context>
<name>EditAddressDialog</name>
@@ -938,9 +1006,25 @@
<source>&amp;Save Image...</source>
<translation>&amp;Konservi Bildon...</translation>
</message>
+ <message>
+ <source>Address</source>
+ <translation>Adreso</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etikedo</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Etikedo</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(neniu etikedo)</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -1020,7 +1104,11 @@
<source>S&amp;end</source>
<translation>Ŝendi</translation>
</message>
- </context>
+ <message>
+ <source>(no label)</source>
+ <translation>(neniu etikedo)</translation>
+ </message>
+</context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -1183,9 +1271,33 @@
</context>
<context>
<name>TransactionTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Etikedo</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(neniu etikedo)</translation>
+ </message>
</context>
<context>
<name>TransactionView</name>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Perkome disigita dosiero (*.csv)</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etikedo</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adreso</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>ekspotado malsukcesinta</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
diff --git a/src/qt/locale/bitcoin_es.ts b/src/qt/locale/bitcoin_es.ts
index 5ba44a954c..1cac03951c 100644
--- a/src/qt/locale/bitcoin_es.ts
+++ b/src/qt/locale/bitcoin_es.ts
@@ -330,6 +330,10 @@
<translation>Pulsar para volver a habilitar la actividad de red.</translation>
</message>
<message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>Sincronizando cabeceras (%1%)</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>Reindexando bloques en disco...</translation>
</message>
@@ -441,10 +445,6 @@
<source>Processing blocks on disk...</source>
<translation>Procesando bloques en disco...</translation>
</message>
- <message>
- <source>No block source available...</source>
- <translation>Ninguna fuente de bloques disponible...</translation>
- </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation><numerusform>%n bloque procesado del historial de transacciones.</numerusform><numerusform>%n bloques procesados del historial de transacciones.</numerusform></translation>
@@ -486,6 +486,10 @@
<translation>%1 cliente</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>Conectando a pares...</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>Actualizando...</translation>
</message>
@@ -891,7 +895,7 @@
</message>
<message>
<source>Number of blocks left</source>
- <translation>Número de bloques dejados</translation>
+ <translation>Número de bloques restantes</translation>
</message>
<message>
<source>Unknown...</source>
@@ -1705,6 +1709,10 @@
<translation>Prohibir para</translation>
</message>
<message>
+ <source>&amp;Unban</source>
+ <translation>&amp;Unbano</translation>
+ </message>
+ <message>
<source>Welcome to the %1 RPC console.</source>
<translation>Bienvenido a la consola RPC %1.</translation>
</message>
@@ -1717,6 +1725,14 @@
<translation>Escriba &lt;b&gt;help&lt;/b&gt; para ver un resumen de los comandos disponibles.</translation>
</message>
<message>
+ <source>WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramification of a command.</source>
+ <translation>ADVERTENCIA: Hay estafadores activos diciendo a los usuarios que escriban comandos aquí y robando el contenido de sus monederos. No utilice esta consola sin entender completamente la repercusión de un comando.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled</source>
+ <translation>Actividad de red deshabilitada</translation>
+ </message>
+ <message>
<source>%1 B</source>
<translation>%1 B</translation>
</message>
@@ -1836,6 +1852,10 @@
<translation>Eliminar</translation>
</message>
<message>
+ <source>Copy URI</source>
+ <translation>Copiar URI</translation>
+ </message>
+ <message>
<source>Copy label</source>
<translation>Copiar capa</translation>
</message>
@@ -2061,6 +2081,10 @@
<translation>Polvo:</translation>
</message>
<message>
+ <source>Confirmation time target:</source>
+ <translation>Objetivo de tiempo de confirmación</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>Vaciar &amp;todo</translation>
</message>
@@ -2153,6 +2177,10 @@
<translation>¡Falló la creación de transacción!</translation>
</message>
<message>
+ <source>The transaction was rejected with the following reason: %1</source>
+ <translation>Se ha rechazado la transacción por la siguiente razón: %1</translation>
+ </message>
+ <message>
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation>Una comisión mayor que %1 se considera una cuota irracionalmente alta.</translation>
</message>
@@ -2160,10 +2188,18 @@
<source>Payment request expired.</source>
<translation>Solicitud de pago caducada.</translation>
</message>
+ <message numerus="yes">
+ <source>%n block(s)</source>
+ <translation><numerusform>%n bloque</numerusform><numerusform>%n bloques</numerusform></translation>
+ </message>
<message>
<source>Pay only the required fee of %1</source>
<translation>Pagar únicamente la comisión solicitada de %1</translation>
</message>
+ <message numerus="yes">
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation><numerusform>Estimado para empezar la confirmación dentro de %n bloque.</numerusform><numerusform>Estimado para empezar la confirmación dentro de %n bloques.</numerusform></translation>
+ </message>
<message>
<source>Warning: Invalid Bitcoin address</source>
<translation>Alerta: dirección Bitcoin inválida</translation>
@@ -2173,6 +2209,14 @@
<translation>Alerta: dirección cambiada desconocida</translation>
</message>
<message>
+ <source>Confirm custom change address</source>
+ <translation>Confirmar dirección de cambio personalizada</translation>
+ </message>
+ <message>
+ <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source>
+ <translation>La dirección que ha seleccionado para cambiar no es parte de este monedero. ninguno o todos los fondos de su monedero pueden ser enviados a esta dirección. ¿Está seguro?</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(sin etiqueta)</translation>
</message>
@@ -2433,6 +2477,10 @@
</context>
<context>
<name>TransactionDesc</name>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>Abrir para %n bloque más</numerusform><numerusform>Abrir para %n bloques más</numerusform></translation>
+ </message>
<message>
<source>Open until %1</source>
<translation>Abierto hasta %1</translation>
@@ -2477,6 +2525,10 @@
<source>, has not been successfully broadcast yet</source>
<translation>, no ha sido emitido con éxito aún</translation>
</message>
+ <message numerus="yes">
+ <source>, broadcast through %n node(s)</source>
+ <translation><numerusform>, transmitir a través de %n nodo</numerusform><numerusform>, transmitir a través de %n nodos</numerusform></translation>
+ </message>
<message>
<source>Date</source>
<translation>Fecha</translation>
@@ -2517,6 +2569,10 @@
<source>Credit</source>
<translation>Credito</translation>
</message>
+ <message numerus="yes">
+ <source>matures in %n more block(s)</source>
+ <translation><numerusform>disponible en %n bloque más</numerusform><numerusform>disponible en %n bloques más</numerusform></translation>
+ </message>
<message>
<source>not accepted</source>
<translation>no aceptada</translation>
@@ -2554,6 +2610,10 @@
<translation>Identificador de transacción (ID)</translation>
</message>
<message>
+ <source>Transaction total size</source>
+ <translation>Tamaño total de transacción</translation>
+ </message>
+ <message>
<source>Output index</source>
<translation>Indice de salida</translation>
</message>
@@ -2615,6 +2675,10 @@
<source>Label</source>
<translation>Etiqueta</translation>
</message>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>Abrir para %n bloque más</numerusform><numerusform>Abrir para %n bloques más</numerusform></translation>
+ </message>
<message>
<source>Open until %1</source>
<translation>Abierto hasta %1</translation>
@@ -2948,6 +3012,18 @@
</translation>
</message>
<message>
+ <source>Accept connections from outside (default: 1 if no -proxy or -connect/-noconnect)</source>
+ <translation>Aceptar conexiones desde el exterior (predeterminado: 1 si no -proxy o -connect/-desconectar)</translation>
+ </message>
+ <message>
+ <source>Connect only to the specified node(s); -noconnect or -connect=0 alone to disable automatic connections</source>
+ <translation>Conectar sólo al nodo(s) especificado; -no conectar or -conectar=solo 0 para deshabilitar conexiones automáticas</translation>
+ </message>
+ <message>
+ <source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
+ <translation>Distribuido bajo la licencia de software MIT, vea el archivo adjunto %s o %s</translation>
+ </message>
+ <message>
<source>If &lt;category&gt; is not supplied or if &lt;category&gt; = 1, output all debugging information.</source>
<translation>Si &lt;category&gt; no es proporcionado o si &lt;category&gt; =1, muestra toda la información de depuración.</translation>
</message>
@@ -2960,10 +3036,6 @@
<translation>Poda: la ultima sincronizacion del monedero sobrepasa los datos podados. Necesitas reindexar con -reindex (o descargar la cadena de bloques de nuevo en el caso de un nodo podado)</translation>
</message>
<message>
- <source>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, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Reduce los requisitos de almacenaje podando (eliminando) los bloques viejos. Este modo es incompatible con -txindex y -rescan. Advertencia: Revertir este ajuste requiere volver a descargar la cadena de bloques al completo. (predeterminado: 0 = deshabilitar la poda de bloques, &gt;%u = objetivo de tamaño en MiB para usar para los archivos de bloques)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Nos es posible re-escanear en modo podado.Necesitas utilizar -reindex el cual descargara la cadena de bloques al completo de nuevo.</translation>
</message>
@@ -3029,6 +3101,14 @@
<translation>Ejecutar comando cuando una transacción del monedero cambia (%s en cmd se remplazará por TxID)</translation>
</message>
<message>
+ <source>Extra transactions to keep in memory for compact block reconstructions (default: %u)</source>
+ <translation>Transacciones extra a mantener en la memoria para reconstrucciones de bloque compacto (predeterminado: %u)</translation>
+ </message>
+ <message>
+ <source>If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)</source>
+ <translation>Si este bloque está en la cadena asuma que sus predecesores y él son válidos y potencialmente se saltan su script de verificación (0 para verificar todo, predeterminado: %s, testnet: %s)</translation>
+ </message>
+ <message>
<source>Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)</source>
<translation>Ajuste máximo permitido del tiempo offset medio de pares. La perspectiva local de tiempo se verá influenciada por los pares anteriores y posteriores a esta cantidad. (Por defecto: %u segundos)</translation>
</message>
@@ -3045,6 +3125,14 @@
<translation>Contribuya si encuentra %s de utilidad. Visite %s para mas información acerca del programa.</translation>
</message>
<message>
+ <source>Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, &gt;%u = automatically prune block files to stay under the specified target size in MiB)</source>
+ <translation>Reducir los requerimientos de almacenamiento habilitando la poda (eliminación) de los bloques viejos. Esto permite que la cadena de bloqueo RPC sea llamada para eliminar bloques específicos, y habilita la poda automática de bloques viejos si se provee el tamaño de un objetivo en MiB. Este modo es incompatible con -txindex and -rescan. Precaución: Revertir este ajuste requiere volver a descargar la cadena de bloqueo completa. (predefinido: 0 = deshabilita bloques de poda, 1 = permite la poda manual mediante RPC, &gt;%u = elimina automáticamente los archivos de bloqueo para permanecer bajo el tamaño del objetivo especificado en MiB)</translation>
+ </message>
+ <message>
+ <source>Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)</source>
+ <translation>Establecer la tasa más baja (en %s/kB) por transacciones para incluirse en la creación de bloque. (predeterminado: %s)</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>Establecer el número de hilos (threads) de verificación de scripts (entre %u y %d, 0 = automático, &lt;0 = dejar libres ese número de núcleos; predeterminado: %d)</translation>
</message>
@@ -3053,6 +3141,10 @@
<translation>La base de datos de bloques contiene un bloque que parece ser del futuro. Esto puede ser porque la fecha y hora de tu ordenador están mal ajustados. Reconstruye la base de datos de bloques solo si estas seguro de que la fecha y hora de tu ordenador estan ajustados correctamente.</translation>
</message>
<message>
+ <source>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source>
+ <translation>Esta es una versión de prueba prelanzada - utilícelo a su propio riesgo - no lo utilice para aplicaciones de minería o comerciales</translation>
+ </message>
+ <message>
<source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source>
<translation>No es posible reconstruir la base de datos a un estado anterior. Debe descargar de nuevo la cadena de bloques.</translation>
</message>
@@ -3061,6 +3153,22 @@
<translation>Utiliza UPnP para asignar el puerto de escucha (predeterminado: 1 cuando esta escuchando sin -proxy)</translation>
</message>
<message>
+ <source>Username and hashed password for JSON-RPC connections. The field &lt;userpw&gt; comes in the format: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=&lt;USERNAME&gt;/rpcpassword=&lt;PASSWORD&gt; pair of arguments. This option can be specified multiple times</source>
+ <translation>Nombre de usuario y contraseña numerada para conexiones JSON-RPC. El campo &lt;userpw&gt; viene en el formato: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. Un script canónico de python está incluído en compartir/usuario rpc. Entonces el cliente se conecta normalmente utilizando la pareja de argumentos usuario rpc=&lt;USERNAME&gt;/contraseña rpc=&lt;PASSWORD&gt;. Esta opción puede ser especificada múltiples veces</translation>
+ </message>
+ <message>
+ <source>Wallet will not create transactions that violate mempool chain limits (default: %u)</source>
+ <translation>El monedero no creará transacciones que violen los límites de la cadena mempool (predeterminado: %u)</translation>
+ </message>
+ <message>
+ <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
+ <translation>Advertencia: ¡La red no parece coincidir del todo! Algunos mineros parecen estar experimentando problemas.</translation>
+ </message>
+ <message>
+ <source>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source>
+ <translation>Advertencia: ¡No parecemos estar del todo con nuestros pares! Puede que necesite actualizarse, o puede que otros nodos necesiten actualizarse.</translation>
+ </message>
+ <message>
<source>You need to rebuild the database using -reindex-chainstate to change -txindex</source>
<translation>Necesita reconstruir la base de datos usando -reindex-chainstate para cambiar -txindex</translation>
</message>
@@ -3093,6 +3201,10 @@
<translation>No se puede resolver -%s direccion: '%s'</translation>
</message>
<message>
+ <source>Chain selection options:</source>
+ <translation>Opciones de selección en cadena:</translation>
+ </message>
+ <message>
<source>Change index out of range</source>
<translation>Cambio de indice fuera de rango</translation>
</message>
@@ -3289,6 +3401,10 @@
<translation>Usar UPnP para asignar el puerto de escucha (predeterminado:: %u)</translation>
</message>
<message>
+ <source>Use the test chain</source>
+ <translation>Utilice la cadena de prueba</translation>
+ </message>
+ <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation>El comentario del Agente de Usuario (%s) contiene caracteres inseguros.</translation>
</message>
@@ -3583,10 +3699,27 @@
<translation>Mostrar depuración (por defecto: %u, proporcionar &lt;category&gt; es opcional)</translation>
</message>
<message>
+ <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect/-noconnect)</source>
+ <translation>Preguntar por direcciones pares al buscar DNS, si baja en las direcciones (predeterminado: 1 a menos que -connect/-noconnect)</translation>
+ </message>
+ <message>
+ <source>Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(1) (default: %d)</source>
+ <translation>https://www.transifex.com/joyful-world/breaking-english/
+Establecer la serialización de las transacciones sin procesar o el bloque hex devuelto en non-verbose mode, non-segwit(O) o segwit(1) (default: %d)</translation>
+ </message>
+ <message>
<source>Support filtering of blocks and transaction with bloom filters (default: %u)</source>
<translation>Admite filtrado de bloques, y transacciones con filtros Bloom. Reduce la carga de red. ( por defecto :%u)</translation>
</message>
<message>
+ <source>This is the transaction fee you may pay when fee estimates are not available.</source>
+ <translation>Esta es la tarifa de cuota que debe pagar cuando las estimaciones de tarifas no estén disponibles.</translation>
+ </message>
+ <message>
+ <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit %s and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
+ <translation>Este producto incluye software desarrollado por el Proyecto OpenSSL para utilizarlo en el juego de herramientas OpenSSL %s y software criptográfico escrito por Eric Young y software UPnP escrito por Thomas Bernard.</translation>
+ </message>
+ <message>
<source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source>
<translation>La longitud total de la cadena de versión de red ( %i ) supera la longitud máxima ( %i ) . Reducir el número o tamaño de uacomments .</translation>
</message>
@@ -3619,6 +3752,10 @@
<translation>Los pares de listas blancas que se conectan desde la dirección IP dada (por ejemplo, 1.2.3.4) o la red marcada CIDR (por ejemplo, 1.2.3.0/24). Se puede especificar varias veces.</translation>
</message>
<message>
+ <source>%s is set very high!</source>
+ <translation>¡%s se establece muy alto!</translation>
+ </message>
+ <message>
<source>(default: %s)</source>
<translation>(predeterminado: %s)</translation>
</message>
@@ -3639,6 +3776,10 @@
<translation>Dirección -proxy inválida: '%s'</translation>
</message>
<message>
+ <source>Keypool ran out, please call keypoolrefill first</source>
+ <translation>Keypool se ha agotado, llame a keypoolrefill primero</translation>
+ </message>
+ <message>
<source>Listen for JSON-RPC connections on &lt;port&gt; (default: %u or testnet: %u)</source>
<translation>Escuchar conexiones JSON-RPC en &lt;puerto&gt; (predeterminado: %u o testnet: %u)</translation>
</message>
@@ -3675,6 +3816,10 @@
<translation>Relay non-P2SH multisig (default: %u)</translation>
</message>
<message>
+ <source>Send transactions with full-RBF opt-in enabled (default: %u)</source>
+ <translation>Enviar transacciones con full-RBF opt-in habilitado (predeterminado: %u)</translation>
+ </message>
+ <message>
<source>Set key pool size to &lt;n&gt; (default: %u)</source>
<translation>Ajustar el número de claves en reserva &lt;n&gt; (predeterminado: %u)</translation>
</message>
@@ -3707,10 +3852,34 @@
<translation>Iniciando funciones de red...</translation>
</message>
<message>
+ <source>The wallet will avoid paying less than the minimum relay fee.</source>
+ <translation>El monedero evitará pagar menos que la cuota de retransmisión mínima.</translation>
+ </message>
+ <message>
+ <source>This is the minimum transaction fee you pay on every transaction.</source>
+ <translation>Esta es la tarifa mínima de transacción que usted paga en cada transacción.</translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you will pay if you send a transaction.</source>
+ <translation>Esta es la cuota de transacción que pagará si envía una transacción.</translation>
+ </message>
+ <message>
<source>Threshold for disconnecting misbehaving peers (default: %u)</source>
<translation>Umbral para la desconexión de pares con mal comportamiento (predeterminado: %u)</translation>
</message>
<message>
+ <source>Transaction amounts must not be negative</source>
+ <translation>Las cantidades de transacción no deben ser negativa</translation>
+ </message>
+ <message>
+ <source>Transaction has too long of a mempool chain</source>
+ <translation>La transacción tiene demasiado tiempo de una cadena de mempool</translation>
+ </message>
+ <message>
+ <source>Transaction must have at least one recipient</source>
+ <translation>La transacción debe de tener al menos un receptor</translation>
+ </message>
+ <message>
<source>Unknown network specified in -onlynet: '%s'</source>
<translation>La red especificada en -onlynet '%s' es desconocida</translation>
</message>
diff --git a/src/qt/locale/bitcoin_es_DO.ts b/src/qt/locale/bitcoin_es_DO.ts
index eb6583083b..77e6ef16f3 100644
--- a/src/qt/locale/bitcoin_es_DO.ts
+++ b/src/qt/locale/bitcoin_es_DO.ts
@@ -238,10 +238,6 @@
<translation>&amp;Opciones de linea de comando</translation>
</message>
<message>
- <source>No block source available...</source>
- <translation>Ninguna fuente de bloques disponible ...</translation>
- </message>
- <message>
<source>%1 behind</source>
<translation>%1 atrás</translation>
</message>
diff --git a/src/qt/locale/bitcoin_es_ES.ts b/src/qt/locale/bitcoin_es_ES.ts
index c971d664d8..e0ddf7d530 100644
--- a/src/qt/locale/bitcoin_es_ES.ts
+++ b/src/qt/locale/bitcoin_es_ES.ts
@@ -318,6 +318,22 @@
<translation>Abrir &amp;URI...</translation>
</message>
<message>
+ <source>Click to disable network activity.</source>
+ <translation>Haz click para desactivar la actividad de red.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>Actividad de red desactivada.</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>Haz click para reactivar la actividad de red.</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>Sincronizando cabeceras (%1%)...</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>Reindexando bloques en disco...</translation>
</message>
@@ -429,10 +445,6 @@
<source>Processing blocks on disk...</source>
<translation>Procesando bloques en disco...</translation>
</message>
- <message>
- <source>No block source available...</source>
- <translation>Ninguna fuente de bloques disponible ...</translation>
- </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation><numerusform>%n bloque procesado del historial de transacciones.</numerusform><numerusform>%n bloques procesados del historial de transacciones.</numerusform></translation>
@@ -474,6 +486,10 @@
<translation>%1 cliente</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>Conectando a pares...</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>Actualizando...</translation>
</message>
@@ -523,7 +539,11 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>El monedero está &lt;b&gt;cifrado&lt;/b&gt; y actualmente &lt;b&gt;bloqueado&lt;/b&gt;</translation>
</message>
- </context>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>Ha ocurrido un error fatal. Bitcoin no puede continuar de manera segura y se cerrará.</translation>
+ </message>
+</context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -858,14 +878,42 @@
<translation>Formulario</translation>
</message>
<message>
+ <source>Number of blocks left</source>
+ <translation>Número de bloques restantes</translation>
+ </message>
+ <message>
+ <source>Unknown...</source>
+ <translation>Desconocido...</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation>Hora del último bloque</translation>
</message>
<message>
+ <source>Progress</source>
+ <translation>Progreso</translation>
+ </message>
+ <message>
+ <source>Progress increase per hour</source>
+ <translation>Incremento del progreso por hora</translation>
+ </message>
+ <message>
+ <source>calculating...</source>
+ <translation>calculando...</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation>Tiempo estimado restante hasta sincronización completa</translation>
+ </message>
+ <message>
<source>Hide</source>
<translation>Ocultar</translation>
</message>
- </context>
+ <message>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation>Desconocido. Sincronizando cabeceras (%1)...</translation>
+ </message>
+</context>
<context>
<name>OpenURIDialog</name>
<message>
@@ -1300,7 +1348,15 @@
<source>Node/Service</source>
<translation>Nodo/Servicio</translation>
</message>
- </context>
+ <message>
+ <source>NodeId</source>
+ <translation>NodeId</translation>
+ </message>
+ <message>
+ <source>Ping</source>
+ <translation>Ping</translation>
+ </message>
+</context>
<context>
<name>QObject</name>
<message>
@@ -1343,9 +1399,17 @@
<source>%1 and %2</source>
<translation>%1 y %2</translation>
</message>
- </context>
+ <message>
+ <source>%1 didn't yet exit safely...</source>
+ <translation>%1 aún no ha salido de manera segura...</translation>
+ </message>
+</context>
<context>
<name>QObject::QObject</name>
+ <message>
+ <source>Error: Specified data directory "%1" does not exist.</source>
+ <translation>Error: directorio especificado "%1" no existe.</translation>
+ </message>
</context>
<context>
<name>QRImageWidget</name>
@@ -1716,6 +1780,10 @@
<translation>Eliminar</translation>
</message>
<message>
+ <source>Copy URI</source>
+ <translation>Copiar URL</translation>
+ </message>
+ <message>
<source>Copy label</source>
<translation>Copiar capa</translation>
</message>
@@ -1941,6 +2009,10 @@
<translation>Polvo:</translation>
</message>
<message>
+ <source>Confirmation time target:</source>
+ <translation>Tiempo objetivo de confirmación:</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>Vaciar &amp;todo</translation>
</message>
@@ -2840,10 +2912,6 @@
<translation>Poda: la ultima sincronizacion de la cartera sobrepasa los datos podados. Necesitas reindexar con -reindex (o descargar la cadena de bloques de nuevo en el caso de un nodo podado)</translation>
</message>
<message>
- <source>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, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Reduce los requisitos de almacenaje podando (eliminando) los bloques viejos. Este modo es incompatible con -txindex y -rescan. Advertencia: Revertir este ajuste requiere volver a descargar la cadena de bloques al completo. (predeterminado: 0 = deshabilitar la poda de bloques, &gt;%u = objetivo de tamaño en MiB para usar para los archivos de bloques)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Nos es posible re-escanear en modo podado.Necesitas utilizar -reindex el cual descargara la cadena de bloques al completo de nuevo.</translation>
</message>
@@ -3491,6 +3559,10 @@
<translation>Aviso: fichero de monedero corrupto, datos recuperados! Original %s guardado como %s en %s; si su balance de transacciones es incorrecto, debe restaurar desde una copia de seguridad.</translation>
</message>
<message>
+ <source>%s is set very high!</source>
+ <translation>%s es demasiado alto!</translation>
+ </message>
+ <message>
<source>(default: %s)</source>
<translation>(predeterminado: %s)</translation>
</message>
@@ -3547,6 +3619,10 @@
<translation>Relay non-P2SH multisig (default: %u)</translation>
</message>
<message>
+ <source>Send transactions with full-RBF opt-in enabled (default: %u)</source>
+ <translation>Enviar transaciones con RBF-completo opt-in activado (default: %u)</translation>
+ </message>
+ <message>
<source>Set key pool size to &lt;n&gt; (default: %u)</source>
<translation>Ajustar el número de claves en reserva &lt;n&gt; (predeterminado: %u)</translation>
</message>
diff --git a/src/qt/locale/bitcoin_es_MX.ts b/src/qt/locale/bitcoin_es_MX.ts
index bf8f0ceb88..ffa80a10bd 100644
--- a/src/qt/locale/bitcoin_es_MX.ts
+++ b/src/qt/locale/bitcoin_es_MX.ts
@@ -3,7 +3,7 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation>Click derecho para editar tu dirección o etiqueta</translation>
+ <translation>Click derecho para editar dirección o etiqueta</translation>
</message>
<message>
<source>Create a new address</source>
@@ -31,7 +31,7 @@
</message>
<message>
<source>Export the data in the current tab to a file</source>
- <translation>Exportar la información en la tabla actual a un archivo</translation>
+ <translation>Exportar la información en la pestaña actual a un archivo</translation>
</message>
<message>
<source>&amp;Export</source>
@@ -596,6 +596,10 @@
</context>
<context>
<name>WalletView</name>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Exportar la información en la pestaña actual a un archivo</translation>
+ </message>
</context>
<context>
<name>bitcoin-core</name>
diff --git a/src/qt/locale/bitcoin_et.ts b/src/qt/locale/bitcoin_et.ts
index 0512b9f117..313d5e3be1 100644
--- a/src/qt/locale/bitcoin_et.ts
+++ b/src/qt/locale/bitcoin_et.ts
@@ -214,6 +214,10 @@
</context>
<context>
<name>BanTableModel</name>
+ <message>
+ <source>IP/Netmask</source>
+ <translation>IP/Võrgumask</translation>
+ </message>
</context>
<context>
<name>BitcoinGUI</name>
@@ -385,10 +389,6 @@
<source>Processing blocks on disk...</source>
<translation>Kõvakettal olevate plokkide töötlemine...</translation>
</message>
- <message>
- <source>No block source available...</source>
- <translation>Plokkide allikas pole saadaval...</translation>
- </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation><numerusform>Töödeldud %n plokk transaktsioonide ajaloost.</numerusform><numerusform>Töödeldud %n plokki transaktsioonide ajaloost.</numerusform></translation>
@@ -792,6 +792,10 @@
<translation>&amp;Aken</translation>
</message>
<message>
+ <source>Hide tray icon</source>
+ <translation>Peida tegumiriba ikoon</translation>
+ </message>
+ <message>
<source>Show only a tray icon after minimizing the window.</source>
<translation>Minimeeri systray alale.</translation>
</message>
@@ -908,9 +912,29 @@
<translation>N/A</translation>
</message>
<message>
+ <source>%1 ms</source>
+ <translation>%1 ms</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation><numerusform>%n tund</numerusform><numerusform>%n tundi</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation><numerusform>%n päev</numerusform><numerusform>%n päeva</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation><numerusform>%n nädal</numerusform><numerusform>%n nädalat</numerusform></translation>
+ </message>
+ <message>
<source>%1 and %2</source>
<translation>%1 ja %2</translation>
</message>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation><numerusform>%n aasta</numerusform><numerusform>%n aastat</numerusform></translation>
+ </message>
</context>
<context>
<name>QObject::QObject</name>
diff --git a/src/qt/locale/bitcoin_et_EE.ts b/src/qt/locale/bitcoin_et_EE.ts
index d96ffa42f5..9b0c908381 100644
--- a/src/qt/locale/bitcoin_et_EE.ts
+++ b/src/qt/locale/bitcoin_et_EE.ts
@@ -88,6 +88,10 @@
<translation>Sisestatud paroolid ei kattu.</translation>
</message>
<message>
+ <source>Wallet unlock failed</source>
+ <translation>Rahakoti lahtilukustamine ebaõnnestus</translation>
+ </message>
+ <message>
<source>Wallet decryption failed</source>
<translation>Rahakoti dekrüpteerimine ebaõnnestus</translation>
</message>
@@ -110,6 +114,14 @@
<translation>&amp;Ülevaade</translation>
</message>
<message>
+ <source>Quit application</source>
+ <translation>Välju rakendusest</translation>
+ </message>
+ <message>
+ <source>&amp;Options...</source>
+ <translation>&amp;Valikud...</translation>
+ </message>
+ <message>
<source>Open &amp;URI...</source>
<translation>Ava &amp;URI...</translation>
</message>
@@ -126,14 +138,30 @@
<translation>Rahakott</translation>
</message>
<message>
+ <source>&amp;Send</source>
+ <translation>&amp;Saada</translation>
+ </message>
+ <message>
+ <source>&amp;Show / Hide</source>
+ <translation>&amp;Näita / Peida</translation>
+ </message>
+ <message>
<source>&amp;File</source>
<translation>&amp;Fail</translation>
</message>
<message>
+ <source>&amp;Settings</source>
+ <translation>&amp;Seaded</translation>
+ </message>
+ <message>
<source>&amp;Help</source>
<translation>&amp;Abi</translation>
</message>
<message>
+ <source>&amp;Command-line options</source>
+ <translation>&amp;Käsurea valikud</translation>
+ </message>
+ <message>
<source>%1 behind</source>
<translation>%1 ajast maas</translation>
</message>
@@ -204,6 +232,10 @@
<context>
<name>EditAddressDialog</name>
<message>
+ <source>&amp;Address</source>
+ <translation>&amp;Aadress</translation>
+ </message>
+ <message>
<source>New key generation failed.</source>
<translation>Uue võtme genereerimine ebaõnnestus.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_fa.ts b/src/qt/locale/bitcoin_fa.ts
index c1061822ca..c9aa1b5624 100644
--- a/src/qt/locale/bitcoin_fa.ts
+++ b/src/qt/locale/bitcoin_fa.ts
@@ -62,6 +62,14 @@
<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>&amp;Copy Address</source>
+ <translation>کپی کردن آدرس</translation>
+ </message>
+ <message>
<source>Copy &amp;Label</source>
<translation>کپی و برچسب‌&amp;گذاری</translation>
</message>
@@ -69,6 +77,14 @@
<source>&amp;Edit</source>
<translation>&amp;ویرایش</translation>
</message>
+ <message>
+ <source>Export Address List</source>
+ <translation>صدور لیست آدرس ها</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>صدور موفق نبود</translation>
+ </message>
</context>
<context>
<name>AddressTableModel</name>
@@ -108,14 +124,30 @@
<translation>رمزنگاری کیف پول</translation>
</message>
<message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>این عملیات نیاز به عبارت کیف پول شما برای بازگشایی کیف پول دارد</translation>
+ </message>
+ <message>
<source>Unlock wallet</source>
<translation>باز کردن قفل کیف پول</translation>
</message>
<message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>این عملیات نیاز به عبارت کیف پول شما برای رمزگشایی کیف پول دارد.</translation>
+ </message>
+ <message>
<source>Decrypt wallet</source>
<translation>رمزگشایی کیف پول</translation>
</message>
<message>
+ <source>Change passphrase</source>
+ <translation>تغییر گذرواژه</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>عبارت کهنه و جدید کیف پول را وارد کنید.</translation>
+ </message>
+ <message>
<source>Confirm wallet encryption</source>
<translation>تأیید رمزنگاری کیف پول</translation>
</message>
@@ -250,6 +282,18 @@
<translation>باز کردن &amp;آدرس</translation>
</message>
<message>
+ <source>Click to disable network activity.</source>
+ <translation>برای غیر فعال کردن فعالیت شبکه کلیک کنید.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>فعالیت شبکه غیر فعال شد.</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>برای فعال کردن دوباره فعالیت شبکه کلیک کنید.</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>بازنشانی بلوک‌ها روی دیسک...</translation>
</message>
@@ -357,10 +401,6 @@
<source>Processing blocks on disk...</source>
<translation>پردازش بلوک‌ها روی دیسک...</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></translation>
@@ -511,6 +551,10 @@
<translation>تأیید شده</translation>
</message>
<message>
+ <source>Copy address</source>
+ <translation>کپی ادرس</translation>
+ </message>
+ <message>
<source>Copy label</source>
<translation>کپی برچسب</translation>
</message>
@@ -535,6 +579,18 @@
<translation>کپی تعداد</translation>
</message>
<message>
+ <source>Copy fee</source>
+ <translation>رونوشت کارمزد</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>کپی کردن بایت ها</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>کپی کردن تغییر</translation>
+ </message>
+ <message>
<source>(%1 locked)</source>
<translation>(%1 قفل شده)</translation>
</message>
@@ -702,10 +758,30 @@
<translation>فرم</translation>
</message>
<message>
+ <source>Unknown...</source>
+ <translation>مشخص نیست</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation>زمان آخرین بلوک</translation>
</message>
<message>
+ <source>Progress</source>
+ <translation>پیشروی</translation>
+ </message>
+ <message>
+ <source>Progress increase per hour</source>
+ <translation>پیشروی در هر ساعت بیشتر میشود</translation>
+ </message>
+ <message>
+ <source>calculating...</source>
+ <translation>در حال محاسبه...</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation>زمان تخمینی تا سینک شدن</translation>
+ </message>
+ <message>
<source>Hide</source>
<translation>پنهان کردن</translation>
</message>
@@ -925,6 +1001,10 @@
</context>
<context>
<name>PaymentServer</name>
+ <message>
+ <source>Invalid payment request.</source>
+ <translation>درخواست پرداخت نامعتبر.</translation>
+ </message>
</context>
<context>
<name>PeerTableModel</name>
@@ -1089,6 +1169,10 @@
<translation>در:</translation>
</message>
<message>
+ <source>Out:</source>
+ <translation>خروجی:</translation>
+ </message>
+ <message>
<source>Debug log file</source>
<translation>فایلِ لاگِ اشکال زدایی</translation>
</message>
@@ -1097,6 +1181,26 @@
<translation>پاکسازی کنسول</translation>
</message>
<message>
+ <source>1 &amp;hour</source>
+ <translation>1 ساعت</translation>
+ </message>
+ <message>
+ <source>1 &amp;day</source>
+ <translation>1 روز</translation>
+ </message>
+ <message>
+ <source>1 &amp;week</source>
+ <translation>1 هفته</translation>
+ </message>
+ <message>
+ <source>1 &amp;year</source>
+ <translation>1 سال</translation>
+ </message>
+ <message>
+ <source>Ban for</source>
+ <translation>محدود شده برای</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>
@@ -1333,6 +1437,18 @@
<translation>کپی مقدار</translation>
</message>
<message>
+ <source>Copy fee</source>
+ <translation>رونوشت کارمزد</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>کپی کردن بایت ها</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>کپی کردن تغییر</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(بدون برچسب)</translation>
</message>
@@ -1519,6 +1635,10 @@
<context>
<name>TransactionView</name>
<message>
+ <source>Copy address</source>
+ <translation>کپی ادرس</translation>
+ </message>
+ <message>
<source>Copy label</source>
<translation>کپی برچسب</translation>
</message>
@@ -1538,6 +1658,10 @@
<source>Address</source>
<translation>آدرس</translation>
</message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>صدور موفق نبود</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
diff --git a/src/qt/locale/bitcoin_fa_IR.ts b/src/qt/locale/bitcoin_fa_IR.ts
index 1e829aff9e..b0acc67b92 100644
--- a/src/qt/locale/bitcoin_fa_IR.ts
+++ b/src/qt/locale/bitcoin_fa_IR.ts
@@ -2,8 +2,12 @@
<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>
+ <translation>گشایش حساب جدید</translation>
</message>
<message>
<source>&amp;New</source>
@@ -37,9 +41,65 @@
<source>&amp;Delete</source>
<translation>حذف</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>C&amp;hoose</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>
+ <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>&amp;Copy Address</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>Exporting Failed</source>
+ <translation>گرفتن خروجی به مشکل خورد</translation>
+ </message>
</context>
<context>
<name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>برچسب</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>آدرس</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -59,6 +119,26 @@
<source>Repeat new passphrase</source>
<translation>رمز/پَس فرِیز را دوباره وارد کنید</translation>
</message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>رمزگذاری کیف پول</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>رمزگشایی کیف پول</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>تغییر رمزعبور</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>تایید رمزگذاری کیف پول</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>کیف پول رمزگذاری شده است</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
@@ -75,7 +155,7 @@
</message>
<message>
<source>&amp;Overview</source>
- <translation>و بازبینی</translation>
+ <translation>بازبینی</translation>
</message>
<message>
<source>Show general overview of wallet</source>
@@ -83,7 +163,7 @@
</message>
<message>
<source>&amp;Transactions</source>
- <translation>و تراکنش</translation>
+ <translation>تراکنش</translation>
</message>
<message>
<source>Browse transaction history</source>
@@ -99,7 +179,7 @@
</message>
<message>
<source>About &amp;Qt</source>
- <translation>درباره و Qt</translation>
+ <translation>درباره Qt</translation>
</message>
<message>
<source>Show information about Qt</source>
@@ -107,15 +187,15 @@
</message>
<message>
<source>&amp;Options...</source>
- <translation>و انتخابها</translation>
+ <translation>انتخاب ها</translation>
</message>
<message>
<source>&amp;Encrypt Wallet...</source>
- <translation>و رمزگذاری wallet</translation>
+ <translation>رمزگذاری کیف پول</translation>
</message>
<message>
<source>&amp;Backup Wallet...</source>
- <translation>و گرفتن نسخه پیشتیبان از wallet</translation>
+ <translation>تهیه نسخه پشتیبان از کیف پول</translation>
</message>
<message>
<source>&amp;Change Passphrase...</source>
@@ -126,16 +206,28 @@
<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>
<message>
<source>Change the passphrase used for wallet encryption</source>
- <translation>رمز مربوط به رمزگذاریِ wallet را تغییر دهید</translation>
+ <translation>رمز عبور مربوط به رمزگذاریِ کیف پول را تغییر دهید</translation>
+ </message>
+ <message>
+ <source>&amp;Debug window</source>
+ <translation>پنجره دیباگ</translation>
+ </message>
+ <message>
+ <source>&amp;Verify message...</source>
+ <translation>تایید پیام</translation>
</message>
<message>
<source>Bitcoin</source>
- <translation>bitcoin</translation>
+ <translation>بیت کوین</translation>
</message>
<message>
<source>Wallet</source>
@@ -143,23 +235,23 @@
</message>
<message>
<source>&amp;Send</source>
- <translation>و ارسال</translation>
+ <translation>ارسال</translation>
</message>
<message>
<source>&amp;Show / Hide</source>
- <translation>&amp;نمایش/ عدم نمایش و</translation>
+ <translation>نمایش/ عدم نمایش</translation>
</message>
<message>
<source>&amp;File</source>
- <translation>و فایل</translation>
+ <translation>فایل</translation>
</message>
<message>
<source>&amp;Settings</source>
- <translation>و تنظیمات</translation>
+ <translation>تنظیمات</translation>
</message>
<message>
<source>&amp;Help</source>
- <translation>و راهنما</translation>
+ <translation>راهنما</translation>
</message>
<message>
<source>Tabs toolbar</source>
@@ -171,7 +263,7 @@
</message>
<message>
<source>Up to date</source>
- <translation>روزآمد</translation>
+ <translation>به روز</translation>
</message>
<message>
<source>Catching up...</source>
@@ -179,7 +271,7 @@
</message>
<message>
<source>Sent transaction</source>
- <translation>ارسال تراکنش</translation>
+ <translation>تراکنش ارسالی</translation>
</message>
<message>
<source>Incoming transaction</source>
@@ -197,21 +289,85 @@
<context>
<name>CoinControlDialog</name>
<message>
+ <source>Coin Selection</source>
+ <translation>انتخاب کوین</translation>
+ </message>
+ <message>
+ <source>Quantity:</source>
+ <translation>مقدار</translation>
+ </message>
+ <message>
<source>Amount:</source>
<translation>میزان وجه:</translation>
</message>
<message>
+ <source>Fee:</source>
+ <translation>هزینه</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation>تغییر</translation>
+ </message>
+ <message>
+ <source>(un)select all</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>Copy address</source>
+ <translation>کپی آدرس</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>کپی برچسب</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>کپی مقدار</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>کپی شناسه تراکنش</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>کپی مقدار</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>کپی هزینه</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>بله</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>خیر</translation>
+ </message>
</context>
<context>
<name>EditAddressDialog</name>
@@ -221,15 +377,35 @@
</message>
<message>
<source>&amp;Label</source>
- <translation>و برچسب</translation>
+ <translation>برچسب</translation>
</message>
<message>
<source>&amp;Address</source>
- <translation>حساب&amp;</translation>
+ <translation>آدرس</translation>
+ </message>
+ <message>
+ <source>New receiving address</source>
+ <translation>آدرس دریافتی جدید</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>آدرس ارسالی جدید</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>ویرایش آدرس دریافتی</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>ویرایش آدرس ارسالی</translation>
</message>
</context>
<context>
<name>FreespaceChecker</name>
+ <message>
+ <source>name</source>
+ <translation>نام</translation>
+ </message>
</context>
<context>
<name>HelpMessageDialog</name>
@@ -245,6 +421,10 @@
<context>
<name>Intro</name>
<message>
+ <source>Welcome</source>
+ <translation>خوش آمدید</translation>
+ </message>
+ <message>
<source>Error</source>
<translation>خطا</translation>
</message>
@@ -255,6 +435,18 @@
<source>Form</source>
<translation>فرم</translation>
</message>
+ <message>
+ <source>Unknown...</source>
+ <translation>ناشناس...</translation>
+ </message>
+ <message>
+ <source>calculating...</source>
+ <translation>در حال محاسبه...</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>پنهان کردن</translation>
+ </message>
</context>
<context>
<name>OpenURIDialog</name>
@@ -263,7 +455,15 @@
<name>OptionsDialog</name>
<message>
<source>Options</source>
- <translation>انتخاب/آپشن</translation>
+ <translation>گزینه ها</translation>
+ </message>
+ <message>
+ <source>MB</source>
+ <translation>مگابایت</translation>
+ </message>
+ <message>
+ <source>&amp;Reset Options</source>
+ <translation>تنظیم مجدد گزینه ها</translation>
</message>
<message>
<source>&amp;Network</source>
@@ -274,12 +474,24 @@
<translation>کیف پول</translation>
</message>
<message>
+ <source>&amp;Port:</source>
+ <translation>پورت:</translation>
+ </message>
+ <message>
+ <source>&amp;Window</source>
+ <translation>پنجره</translation>
+ </message>
+ <message>
+ <source>&amp;Display</source>
+ <translation>نمایش</translation>
+ </message>
+ <message>
<source>&amp;OK</source>
- <translation>و تایید</translation>
+ <translation>تایید</translation>
</message>
<message>
<source>&amp;Cancel</source>
- <translation>و رد</translation>
+ <translation>لغو</translation>
</message>
<message>
<source>default</source>
@@ -296,6 +508,26 @@
<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>Available:</source>
+ <translation>در دسترس:</translation>
+ </message>
+ <message>
+ <source>Pending:</source>
+ <translation>در حال انتظار:</translation>
+ </message>
+ <message>
+ <source>Total:</source>
+ <translation>کل:</translation>
+ </message>
+ <message>
+ <source>Spendable:</source>
+ <translation>قابل مصرف:</translation>
+ </message>
+ <message>
+ <source>Recent transactions</source>
+ <translation>تراکنش های اخیر</translation>
+ </message>
</context>
<context>
<name>PaymentServer</name>
@@ -347,22 +579,46 @@
</message>
<message>
<source>&amp;Label:</source>
- <translation>و برچسب</translation>
+ <translation>برچسب:</translation>
</message>
<message>
<source>&amp;Message:</source>
<translation>پیام:</translation>
</message>
- </context>
+ <message>
+ <source>Remove</source>
+ <translation>حذف</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>کپی برچسب</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>کپی مقدار</translation>
+ </message>
+</context>
<context>
<name>ReceiveRequestDialog</name>
<message>
<source>Copy &amp;Address</source>
<translation>کپی آدرس</translation>
</message>
+ <message>
+ <source>Address</source>
+ <translation>آدرس</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>برچسب</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>برچسب</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -375,14 +631,34 @@
<translation>وجوه ناکافی</translation>
</message>
<message>
+ <source>Quantity:</source>
+ <translation>مقدار</translation>
+ </message>
+ <message>
<source>Amount:</source>
<translation>میزان وجه:</translation>
</message>
<message>
+ <source>Fee:</source>
+ <translation>هزینه</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation>تغییر</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>پنهان کردن</translation>
+ </message>
+ <message>
<source>Send to multiple recipients at once</source>
<translation>ارسال همزمان به گیرنده های متعدد</translation>
</message>
<message>
+ <source>Clear &amp;All</source>
+ <translation>پاک کردن همه</translation>
+ </message>
+ <message>
<source>Balance:</source>
<translation>مانده حساب:</translation>
</message>
@@ -394,32 +670,36 @@
<source>S&amp;end</source>
<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>
</context>
<context>
<name>SendCoinsEntry</name>
<message>
<source>A&amp;mount:</source>
- <translation>و میزان وجه</translation>
+ <translation>میزان وجه</translation>
</message>
<message>
<source>Pay &amp;To:</source>
- <translation>پرداخت و به چه کسی</translation>
+ <translation>پرداخت به:</translation>
</message>
<message>
<source>&amp;Label:</source>
- <translation>و برچسب</translation>
- </message>
- <message>
- <source>Alt+A</source>
- <translation>Alt و A</translation>
+ <translation>برچسب:</translation>
</message>
<message>
<source>Paste address from clipboard</source>
- <translation>آدرس را بر کلیپ بورد کپی کنید</translation>
- </message>
- <message>
- <source>Alt+P</source>
- <translation>Alt و P</translation>
+ <translation>استفاده از آدرس کلیپ بورد</translation>
</message>
<message>
<source>Message:</source>
@@ -448,23 +728,39 @@
<name>SignVerifyMessageDialog</name>
<message>
<source>&amp;Sign Message</source>
- <translation>و امضای پیام </translation>
- </message>
- <message>
- <source>Alt+A</source>
- <translation>Alt و A</translation>
+ <translation>امضای پیام </translation>
</message>
<message>
<source>Paste address from clipboard</source>
<translation>آدرس را بر کلیپ بورد کپی کنید</translation>
</message>
<message>
- <source>Alt+P</source>
- <translation>Alt و P</translation>
+ <source>Enter the message you want to sign here</source>
+ <translation>پیامی که می خواهید امضا کنید را اینجا وارد کنید</translation>
+ </message>
+ <message>
+ <source>Signature</source>
+ <translation>امضا</translation>
</message>
<message>
<source>Sign &amp;Message</source>
- <translation>و امضای پیام </translation>
+ <translation>امضای پیام </translation>
+ </message>
+ <message>
+ <source>Clear &amp;All</source>
+ <translation>پاک کردن همه</translation>
+ </message>
+ <message>
+ <source>&amp;Verify Message</source>
+ <translation>تایید پیام</translation>
+ </message>
+ <message>
+ <source>Verify &amp;Message</source>
+ <translation>تایید پیام</translation>
+ </message>
+ <message>
+ <source>The entered address is invalid.</source>
+ <translation>آدرس وارد شده نامعتبر است.</translation>
</message>
</context>
<context>
@@ -479,6 +775,26 @@
</context>
<context>
<name>TransactionDesc</name>
+ <message>
+ <source>Status</source>
+ <translation>وضعیت</translation>
+ </message>
+ <message>
+ <source>Source</source>
+ <translation>منبع</translation>
+ </message>
+ <message>
+ <source>Generated</source>
+ <translation>تولید شده</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>از</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation>به</translation>
+ </message>
</context>
<context>
<name>TransactionDescDialog</name>
@@ -489,9 +805,65 @@
</context>
<context>
<name>TransactionTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>برچسب</translation>
+ </message>
+ <message>
+ <source>Unconfirmed</source>
+ <translation>تایید نشده</translation>
+ </message>
+ <message>
+ <source>Received from</source>
+ <translation>دریافت شده از</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>ارسال شده به</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>استخراج شده</translation>
+ </message>
</context>
<context>
<name>TransactionView</name>
+ <message>
+ <source>Sent to</source>
+ <translation>ارسال شده به</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>استخراج شده</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>کپی آدرس</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>کپی برچسب</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>کپی مقدار</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>کپی شناسه تراکنش</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>برچسب</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>آدرس</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>گرفتن خروجی به مشکل خورد</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
diff --git a/src/qt/locale/bitcoin_fi.ts b/src/qt/locale/bitcoin_fi.ts
index db643e73d2..d13a5639e5 100644
--- a/src/qt/locale/bitcoin_fi.ts
+++ b/src/qt/locale/bitcoin_fi.ts
@@ -41,10 +41,78 @@
<source>&amp;Delete</source>
<translation>&amp;Poista</translation>
</message>
- </context>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Valitse osoite johon kolikot lähetetään</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Valitse osoite kolikoiden vastaanottamiseen</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>V&amp;alitse</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Lähetysosoitteet</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Vastaanotto-osoitteet</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>Nämä ovat Bitcoin-osoitteesi maksujen lähettämistä varten. Tarkista aina määrä ja vastaanotto-osoite ennen kolikoiden lähettämistä.</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>Tässä ovat Bitcoin vastaanotto-osoitteesi. On suositeltavaa käyttää uutta vastaanotto-osoitetta jokaista lähetystä varten.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Kopioi osoite</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Kopioi &amp;nimike</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Muokkaa</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Vie osoitelista</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Pilkuilla erotettu tiedosto (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Vienti epäonnistui</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Virhe tallentaessa osoitelistaa kohteeseen %1. Yritä uudelleen.</translation>
+ </message>
+</context>
<context>
<name>AddressTableModel</name>
- </context>
+ <message>
+ <source>Label</source>
+ <translation>Nimike</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Osoite</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(ei nimikettä)</translation>
+ </message>
+</context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -63,7 +131,95 @@
<source>Repeat new passphrase</source>
<translation>Toista uusi tunnuslause</translation>
</message>
- </context>
+ <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>Kirjoita uusi salauslause lompakolle.&lt;br/&gt;Käytä salauslausetta jossa on joko&lt;b&gt;kymmenen tai useampi satunnainen merkki&lt;/b&gt;, tai&lt;b&gt;vähintään kahdeksan sanaa&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Salaa lompakko</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Tämä toiminto vaatii lompakkosi tunnuslauseen sen avaamiseksi</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Avaa lompakko</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Tämä toiminto vaatii lompakkosia tunnuslauseen salauksen purkuun</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Pura lompakon salaus</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Vaihda salasana</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Syötä vanha ja uusi tunnuslause lompakolle.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Vahvista lompakon salaaminen</translation>
+ </message>
+ <message>
+ <source>Warning: If you encrypt your wallet and lose your passphrase, you will &lt;b&gt;LOSE ALL OF YOUR BITCOINS&lt;/b&gt;!</source>
+ <translation>Varoitus: Jos salaat lompakkosi ja menetät tunnuslauseesi, &lt;b&gt;MENETÄT KAIKKI BITCOINISI&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Oletko varma, että haluat salata lompakkosi?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Lompakko salattiin</translation>
+ </message>
+ <message>
+ <source>%1 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>%1 sulkeutuu lopettaakseen salausprosessin. Muista, että salattukaan lompakko ei täysin suojaa sitä haittaohjelmien aiheuttamilta varkauksilta.</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>TÄRKEÄÄ: Kaikki tekemäsi vanhan lompakon varmuuskopiot pitäisi korvata uusilla suojatuilla varmuuskopioilla. Turvallisuussyistä edelliset varmuuskopiot muuttuvat turhiksi, kun aloitat uuden suojatun lompakon käytön.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Lompakon salaus epäonnistui</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Lompakon salaaminen epäonnistui sisäisen virheen vuoksi. Lompakkoasi ei salattu.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>Annetut salauslauseet eivät täsmää.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Lompakon lukituksen avaaminen epäonnistui</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>Annettu salauslause lompakon avaamiseksi oli väärä.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Lompakon salauksen purkaminen epäonnistui</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>Lompakon salasana vaihdettiin onnistuneesti.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Varoitus: Caps Lock-painike on päällä!</translation>
+ </message>
+</context>
<context>
<name>BanTableModel</name>
<message>
@@ -162,6 +318,22 @@
<translation>Avaa &amp;URI...</translation>
</message>
<message>
+ <source>Click to disable network activity.</source>
+ <translation>Paina poistaaksesi verkkoyhteysilmaisin käytöstä.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>Verkkoyhteysmittari pois käytöstä</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>Paina ottaaksesi verkkoyhteysilmaisin uudelleen käyttöön.</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>Synkronoidaan Tunnisteita (%1%)...</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>Ladataan lohkoindeksiä...</translation>
</message>
@@ -273,10 +445,6 @@
<source>Processing blocks on disk...</source>
<translation>Käsitellään lohkoja levyllä...</translation>
</message>
- <message>
- <source>No block source available...</source>
- <translation>Lohkojen lähdettä ei saatavilla...</translation>
- </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation><numerusform>Prosessoitu %n lohko rahansiirtohistoriasta.</numerusform><numerusform>Prosessoitu %n lohkoa rahansiirtohistoriasta.</numerusform></translation>
@@ -318,6 +486,10 @@
<translation>%1-asiakas</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>Yhdistetään vertaisiin...</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>Saavutetaan verkkoa...</translation>
</message>
@@ -360,6 +532,14 @@
<translation>Saapuva rahansiirto</translation>
</message>
<message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation>HD avaimen generointi on &lt;b&gt;päällä&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation>HD avaimen generointi on &lt;/b&gt;pois päältä&lt;/b&gt;</translation>
+ </message>
+ <message>
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
<translation>Lompakko on &lt;b&gt;salattu&lt;/b&gt; ja tällä hetkellä &lt;b&gt;avoinna&lt;/b&gt;</translation>
</message>
@@ -367,7 +547,11 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Lompakko on &lt;b&gt;salattu&lt;/b&gt; ja tällä hetkellä &lt;b&gt;lukittuna&lt;/b&gt;</translation>
</message>
- </context>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>Peruuttamaton virhe on tapahtunut. Bitcoin ei voi enää jatkaa turvallisesti ja sammutetaan.</translation>
+ </message>
+</context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -438,7 +622,79 @@
<source>Confirmed</source>
<translation>Vahvistettu</translation>
</message>
- </context>
+ <message>
+ <source>Copy address</source>
+ <translation>Kopioi osoite</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopioi nimike</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopioi määrä</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Kopioi transaktion ID</translation>
+ </message>
+ <message>
+ <source>Lock unspent</source>
+ <translation>Lukitse käyttämättömät</translation>
+ </message>
+ <message>
+ <source>Unlock unspent</source>
+ <translation>Avaa käyttämättömien lukitus</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Kopioi kappalemäärä</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Kopioi rahansiirtokulu</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Kopioi rahansiirtokulun jälkeen</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Kopioi tavut</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Kopioi tomu</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Kopioi vaihtorahat</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation>(%1 lukittu)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>kyllä</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>ei</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation>Saattaa vaihdella +/- %1 satoshia per syöte.</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(ei nimikettä)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(vaihtoraha)</translation>
+ </message>
+</context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -461,7 +717,39 @@
<source>&amp;Address</source>
<translation>&amp;Osoite</translation>
</message>
- </context>
+ <message>
+ <source>New receiving address</source>
+ <translation>Uusi vastaanotto-osoite</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Uusi lähetysosoite</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Muokkaa vastaanottavaa osoitetta</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Muokkaa lähettävää osoitetta</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>Antamasi osoite "%1" ei ole kelvollinen Bitcoin-osoite.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book.</source>
+ <translation>Antamasi osoite "%1" on jo osoitekirjassa</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Lompakkoa ei voitu avata.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Uuden avaimen luonti epäonnistui.</translation>
+ </message>
+</context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -590,10 +878,30 @@
<translation>Lomake</translation>
</message>
<message>
+ <source>Unknown...</source>
+ <translation>Tunnistamaton..</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation>Viimeisimmän lohkon aika</translation>
</message>
<message>
+ <source>Progress</source>
+ <translation>Tila</translation>
+ </message>
+ <message>
+ <source>Progress increase per hour</source>
+ <translation>Edistymisen kasvu tunnissa</translation>
+ </message>
+ <message>
+ <source>calculating...</source>
+ <translation>lasketaan..</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation>Arvioitu jäljellä oleva aika, kunnes synkronoitu</translation>
+ </message>
+ <message>
<source>Hide</source>
<translation>Piilota</translation>
</message>
@@ -932,7 +1240,11 @@
<source>Node/Service</source>
<translation>Noodi/Palvelu</translation>
</message>
- </context>
+ <message>
+ <source>Ping</source>
+ <translation>Vasteaika</translation>
+ </message>
+</context>
<context>
<name>QObject</name>
<message>
@@ -978,10 +1290,30 @@
</context>
<context>
<name>QObject::QObject</name>
- </context>
+ <message>
+ <source>Error: %1</source>
+ <translation>Virhe: %1</translation>
+ </message>
+</context>
<context>
<name>QRImageWidget</name>
- </context>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;Tallenna kuva</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>&amp;Kopioi kuva</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>Tallenna QR-koodi</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>PNG kuva (*.png)</translation>
+ </message>
+</context>
<context>
<name>RPCConsole</name>
<message>
@@ -1141,6 +1473,10 @@
<translation>Yhteyskokeilun odotus</translation>
</message>
<message>
+ <source>Min Ping</source>
+ <translation>Pienin vasteaika</translation>
+ </message>
+ <message>
<source>Time Offset</source>
<translation>Ajan poikkeama</translation>
</message>
@@ -1201,6 +1537,10 @@
<translation>1 &amp;vuosi</translation>
</message>
<message>
+ <source>Welcome to the %1 RPC console.</source>
+ <translation>Tervetuloa %1 RPC-konsoliin.</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>Ylös- ja alas-nuolet selaavat historiaa ja &lt;b&gt;Ctrl-L&lt;/b&gt; tyhjentää ruudun.</translation>
</message>
@@ -1327,7 +1667,19 @@
<source>Remove</source>
<translation>Poista</translation>
</message>
- </context>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopioi nimike</translation>
+ </message>
+ <message>
+ <source>Copy message</source>
+ <translation>Kopioi viesti</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopioi määrä</translation>
+ </message>
+</context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -1346,6 +1698,26 @@
<source>&amp;Save Image...</source>
<translation>&amp;Tallenna kuva</translation>
</message>
+ <message>
+ <source>Payment information</source>
+ <translation>Maksutiedot</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Osoite</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Määrä</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Nimike</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Viesti</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
@@ -1353,7 +1725,23 @@
<source>Date</source>
<translation>Aika</translation>
</message>
- </context>
+ <message>
+ <source>Label</source>
+ <translation>Nimike</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Viesti</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(ei nimikettä)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation>Pyydetty</translation>
+ </message>
+</context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1488,7 +1876,47 @@
<source>S&amp;end</source>
<translation>&amp;Lähetä</translation>
</message>
- </context>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Kopioi kappalemäärä</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopioi määrä</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Kopioi rahansiirtokulu</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Kopioi rahansiirtokulun jälkeen</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Kopioi tavut</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Kopioi tomu</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Kopioi vaihtorahat</translation>
+ </message>
+ <message>
+ <source>Total Amount %1</source>
+ <translation>Kokonaismäärä %1</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>tai</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(ei nimikettä)</translation>
+ </message>
+</context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -1570,7 +1998,11 @@
</context>
<context>
<name>SendConfirmationDialog</name>
- </context>
+ <message>
+ <source>Yes</source>
+ <translation>Kyllä</translation>
+ </message>
+</context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1660,7 +2092,11 @@
<source>Reset all verify message fields</source>
<translation>Tyhjennä kaikki varmista-viesti-kentät</translation>
</message>
- </context>
+ <message>
+ <source>Message verified.</source>
+ <translation>Viesti varmistettu.</translation>
+ </message>
+</context>
<context>
<name>SplashScreen</name>
<message>
@@ -1678,9 +2114,53 @@
<context>
<name>TransactionDesc</name>
<message>
+ <source>%1/unconfirmed</source>
+ <translation>%1/vahvistamaton</translation>
+ </message>
+ <message>
+ <source>%1 confirmations</source>
+ <translation>%1 vahvistusta</translation>
+ </message>
+ <message>
<source>Date</source>
<translation>Aika</translation>
</message>
+ <message>
+ <source>Source</source>
+ <translation>Lähde</translation>
+ </message>
+ <message>
+ <source>Generated</source>
+ <translation>Generoitu</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>Lähettäjä</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>tuntematon</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation>Saaja</translation>
+ </message>
+ <message>
+ <source>own address</source>
+ <translation>oma osoite</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Viesti</translation>
+ </message>
+ <message>
+ <source>Comment</source>
+ <translation>Kommentti</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Määrä</translation>
+ </message>
</context>
<context>
<name>TransactionDescDialog</name>
@@ -1695,14 +2175,154 @@
<source>Date</source>
<translation>Aika</translation>
</message>
+ <message>
+ <source>Type</source>
+ <translation>Tyyppi</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Nimike</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Vastaanotettu osoitteella</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Lähetetty vastaanottajalle</translation>
+ </message>
+ <message>
+ <source>Payment to yourself</source>
+ <translation>Maksu itsellesi</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Louhittu</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(ei nimikettä)</translation>
+ </message>
</context>
<context>
<name>TransactionView</name>
<message>
+ <source>All</source>
+ <translation>Kaikki</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>Tänään</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>Tällä viikolla</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>Tässä kuussa</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>Viime kuussa</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>Tänä vuonna</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Vastaanotettu osoitteella</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Lähetetty vastaanottajalle</translation>
+ </message>
+ <message>
+ <source>To yourself</source>
+ <translation>Itsellesi</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Louhittu</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation>Minimimäärä</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Kopioi osoite</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopioi nimike</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopioi määrä</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Kopioi transaktion ID</translation>
+ </message>
+ <message>
+ <source>Edit label</source>
+ <translation>Muokkaa nimeä</translation>
+ </message>
+ <message>
+ <source>Show transaction details</source>
+ <translation>Näytä rahansiirron yksityiskohdat</translation>
+ </message>
+ <message>
+ <source>Export Transaction History</source>
+ <translation>Vie rahansiirtohistoria</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Pilkuilla erotettu tiedosto (*.csv)</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation>Vahvistettu</translation>
+ </message>
+ <message>
<source>Date</source>
<translation>Aika</translation>
</message>
- </context>
+ <message>
+ <source>Type</source>
+ <translation>Tyyppi</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Nimike</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Osoite</translation>
+ </message>
+ <message>
+ <source>ID</source>
+ <translation>ID</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Vienti epäonnistui</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the transaction history to %1.</source>
+ <translation>Rahansiirron historian tallentamisessa tapahtui virhe paikkaan %1.</translation>
+ </message>
+ <message>
+ <source>Exporting Successful</source>
+ <translation>Vienti onnistui</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>vastaanottaja</translation>
+ </message>
+</context>
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
@@ -1712,16 +2332,44 @@
</context>
<context>
<name>WalletFrame</name>
- </context>
+ <message>
+ <source>No wallet has been loaded.</source>
+ <translation>Lomakkoa ei ole ladattu.</translation>
+ </message>
+</context>
<context>
<name>WalletModel</name>
- </context>
+ <message>
+ <source>Send Coins</source>
+ <translation>Lähetä kolikoita</translation>
+ </message>
+</context>
<context>
<name>WalletView</name>
<message>
<source>&amp;Export</source>
<translation>&amp;Vie</translation>
</message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Vie auki olevan välilehden tiedot tiedostoon</translation>
+ </message>
+ <message>
+ <source>Backup Wallet</source>
+ <translation>Varmuuskopioi lompakko</translation>
+ </message>
+ <message>
+ <source>Wallet Data (*.dat)</source>
+ <translation>Lompakkodata (*.dat)</translation>
+ </message>
+ <message>
+ <source>Backup Failed</source>
+ <translation>Varmuuskopio epäonnistui</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation>Varmuuskopio Onnistui</translation>
+ </message>
</context>
<context>
<name>bitcoin-core</name>
@@ -1758,10 +2406,6 @@
<translation>Karsinta: viime lompakon synkronisointi menee karsitun datan taakse. Sinun tarvitsee ajaa -reindex (lataa koko lohkoketju uudelleen tapauksessa jossa karsiva noodi)</translation>
</message>
<message>
- <source>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, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Vähennä levytilan tarvetta karsimalla (poistamalla) vanhoja lohkoja. Tämä tila ei ole yhteensopiva -txindex ja -rescan -parametrien kanssa. Varoitus: Tämän asetuksen peruutus vaatii koko lohkoketjun uudelleenlataamisen. (oletus: 0 = poista karsinta käytöstä, &gt;%u = kohdekoko muodossa MiB jota käytetään lohkotiedostoille) </translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Uudelleenskannaukset eivät ole mahdollisia karsivassa tilassa. Sinun täytyy käyttää -reindex joka lataa koko lohkoketjun uudelleen.</translation>
</message>
@@ -1966,6 +2610,10 @@
<translation>Karsittu tila ei ole yhteensopiva -txindex:n kanssa.</translation>
</message>
<message>
+ <source>Rewinding blocks...</source>
+ <translation>Varmistetaan lohkoja...</translation>
+ </message>
+ <message>
<source>Set database cache size in megabytes (%d to %d, default: %d)</source>
<translation>Aseta tietokannan välimuistin koko megatavuissa (%d - %d, oletus: %d</translation>
</message>
@@ -2202,6 +2850,10 @@
<translation>Käytä erillistä SOCKS5-proxyä tavoittaaksesi vertaisia Tor-piilopalveluiden kautta (oletus: %s)</translation>
</message>
<message>
+ <source>%s is set very high!</source>
+ <translation>%s on asetettu todella korkeaksi!</translation>
+ </message>
+ <message>
<source>(default: %s)</source>
<translation>(oletus: %s)</translation>
</message>
@@ -2286,10 +2938,26 @@
<translation>Käytä vahvistamattomia vaihtorahoja lähetettäessä rahansiirtoja (oletus: %u)</translation>
</message>
<message>
+ <source>Starting network threads...</source>
+ <translation>Käynnistetään verkkoa...</translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you will pay if you send a transaction.</source>
+ <translation>Tämä on lähetyksestä maksettava maksu jonka maksat</translation>
+ </message>
+ <message>
<source>Threshold for disconnecting misbehaving peers (default: %u)</source>
<translation>Aikaväli sopimattomien vertaisten yhteyksien katkaisuun (oletus: %u)</translation>
</message>
<message>
+ <source>Transaction amounts must not be negative</source>
+ <translation>Lähetyksen siirtosumman tulee olla positiivinen</translation>
+ </message>
+ <message>
+ <source>Transaction must have at least one recipient</source>
+ <translation>Lähetyksessä tulee olla ainakin yksi vastaanottaja</translation>
+ </message>
+ <message>
<source>Unknown network specified in -onlynet: '%s'</source>
<translation>Tuntematon verkko -onlynet parametrina: '%s'</translation>
</message>
diff --git a/src/qt/locale/bitcoin_fr.ts b/src/qt/locale/bitcoin_fr.ts
index eef88b43a3..830e6bb05f 100644
--- a/src/qt/locale/bitcoin_fr.ts
+++ b/src/qt/locale/bitcoin_fr.ts
@@ -330,6 +330,10 @@
<translation>Cliquer pour réactiver l'activité réseau.</translation>
</message>
<message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>Synchronisation des en-têtes (%1)...</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>Réindexation des blocs sur le disque...</translation>
</message>
@@ -441,10 +445,6 @@
<source>Processing blocks on disk...</source>
<translation>Traitement des blocs sur le disque...</translation>
</message>
- <message>
- <source>No block source available...</source>
- <translation>Aucune source de blocs disponible...</translation>
- </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation><numerusform>%n bloc d'historique transactionnel a été traité</numerusform><numerusform>%n blocs d'historique transactionnel ont été traités</numerusform></translation>
@@ -486,6 +486,10 @@
<translation>Client %1</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>Connexion aux pairs...</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>Rattrapage…</translation>
</message>
@@ -883,7 +887,7 @@
</message>
<message>
<source>Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source>
- <translation>Les transactions récentes ne sont peut-être pas encore visibles, et par conséquent, le solde de votre porte-monnaie est peut-être erroné. Cette information sera juste une fois que votre porte-monnaie aura fini de se synchroniser avec le réseau Bitcoin, tel que décrit ci-dessous. </translation>
+ <translation>Les transactions récentes ne sont peut-être pas encore visibles et par conséquent le solde de votre porte-monnaie est peut-être erroné. Cette information sera juste quand votre porte-monnaie aura fini de se synchroniser avec le réseau Bitcoin, comme décrit ci-dessous.</translation>
</message>
<message>
<source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source>
@@ -899,7 +903,7 @@
</message>
<message>
<source>Last block time</source>
- <translation>Horodatage du dernier bloc</translation>
+ <translation>Estampille temporelle du dernier bloc</translation>
</message>
<message>
<source>Progress</source>
@@ -1005,7 +1009,7 @@
</message>
<message>
<source>Active command-line options that override above options:</source>
- <translation>Options actives de ligne de commande qui annulent les options ci-dessus :</translation>
+ <translation>Options de ligne de commande actives qui remplacent les options ci-dessus :</translation>
</message>
<message>
<source>Reset all client options to default.</source>
@@ -1077,7 +1081,7 @@
</message>
<message>
<source>Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source>
- <translation>S'affiche, si le mandataire SOCKS5 par défaut fourni est utilisé pour atteindre les pairs par ce type de réseau.</translation>
+ <translation>Indique si le mandataire SOCKS5 par défaut fourni est utilisé pour atteindre des pairs par ce type de réseau.</translation>
</message>
<message>
<source>IPv4</source>
@@ -1362,7 +1366,7 @@
</message>
<message>
<source>NodeId</source>
- <translation>NodeId</translation>
+ <translation>ID de nœud</translation>
</message>
<message>
<source>Ping</source>
@@ -1642,7 +1646,7 @@
</message>
<message>
<source>Last block time</source>
- <translation>Horodatage du dernier bloc</translation>
+ <translation>Estampille temporelle du dernier bloc</translation>
</message>
<message>
<source>&amp;Open</source>
@@ -1998,11 +2002,11 @@
</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>Si cette option est activée, et l'adresse de monnaie rendue est vide ou invalide, la monnaie sera envoyée vers une adresse nouvellement générée.</translation>
+ <translation>Si cette option est activée et l'adresse de monnaie est vide ou invalide, la monnaie sera envoyée vers une adresse nouvellement générée.</translation>
</message>
<message>
<source>Custom change address</source>
- <translation>Adresse personnalisée de monnaie rendue</translation>
+ <translation>Adresse personnalisée de monnaie</translation>
</message>
<message>
<source>Transaction Fee:</source>
@@ -2174,7 +2178,7 @@
</message>
<message>
<source>The transaction was rejected with the following reason: %1</source>
- <translation>La transaction a été rejetée pour la raison suivante: %1</translation>
+ <translation>La transaction a été rejetée pour la raison suivante : %1</translation>
</message>
<message>
<source>A fee higher than %1 is considered an absurdly high fee.</source>
@@ -2202,7 +2206,15 @@
</message>
<message>
<source>Warning: Unknown change address</source>
- <translation>Avertissement : adresse de monnaie rendue inconnue</translation>
+ <translation>Avertissement : adresse de monnaie inconnue</translation>
+ </message>
+ <message>
+ <source>Confirm custom change address</source>
+ <translation>Confimer l'adresse personnalisée de monnaie</translation>
+ </message>
+ <message>
+ <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source>
+ <translation>L'adresse que vous avez sélectionnée pour la monnaie ne fait pas partie de ce porte-monnaie. Les fonds de ce porte-monnaie peuvent en partie ou en totalité être envoyés vers cette adresse. Êtes-vous certain ?</translation>
</message>
<message>
<source>(no label)</source>
@@ -2307,7 +2319,7 @@
</message>
<message>
<source>Do not shut down the computer until this window disappears.</source>
- <translation>Ne pas fermer l'ordinateur jusqu'à la disparition de cette fenêtre.</translation>
+ <translation>Ne pas éteindre l'ordinateur jusqu'à la disparition de cette fenêtre.</translation>
</message>
</context>
<context>
@@ -3022,10 +3034,6 @@
<translation>Élagage : la dernière synchronisation de porte-monnaie va par-delà les données élaguées. Vous devez -reindex (réindexer, télécharger de nouveau toute la chaîne de blocs en cas de nœud élagué)</translation>
</message>
<message>
- <source>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, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Réduire les exigences de stockage en élaguant (supprimant) les anciens blocs. Ce mode est incompatible avec -txindex et -rescan. Avertissement : ramener ce paramètre à sa valeur antérieure exige un nouveau téléchargement de la chaîne de blocs en entier (par défaut : 0 = désactiver l'élagage des blocs, &gt;%u = taille cible en Mio à utiliser pour les fichiers de blocs).</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Les rebalayages sont impossibles en mode élagage. Vous devrez utiliser -reindex, ce qui téléchargera de nouveau la chaîne de blocs en entier.</translation>
</message>
@@ -3090,6 +3098,10 @@
<translation>Exécuter la commande lorsqu'une transaction de porte-monnaie change (%s dans la commande est remplacée par TxID)</translation>
</message>
<message>
+ <source>If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)</source>
+ <translation>Si ce bloc est dans la chaîne, supposer qu'il est valide, ainsi que ces ancêtres, et ignorer potentiellement la vérification de leur script (0 pour tout vérifier, valeur par défaut : %s, réseau de test : %s)</translation>
+ </message>
+ <message>
<source>Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)</source>
<translation>Réglage moyen maximal autorisé de décalage de l'heure d'un pair. La perspective locale du temps peut être influencée par les pairs, en avance ou en retard, de cette valeur. (Par défaut : %u secondes)</translation>
</message>
@@ -3106,6 +3118,14 @@
<translation>Si vous trouvez %s utile, vous pouvez y contribuer. Vous trouverez davantage d'informations à propos du logiciel sur %s.</translation>
</message>
<message>
+ <source>Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, &gt;%u = automatically prune block files to stay under the specified target size in MiB)</source>
+ <translation>Réduire les exigences de stockage en activant l'élagage (suppression) des anciens blocs. Cela permet d'appeler le RPC « pruneblockchain » pour supprimer des blocs précis et active l'élagage automatique des anciens blocs si une taille cible en Mio est fournie. Ce mode n'est pas compatible avec -txindex et -rescan. Avertissement : ramener ce paramètre à sa valeur antérieure exige de retélécharger l'intégralité de la chaîne de blocs (par défaut : 0 = désactiver l'élagage des blocs, 1 = permettre l'élagage manuel par RPC, &gt;%u = élaguer automatiquement les fichiers de blocs pour rester en deçà de la taille cible précisée en Mio).</translation>
+ </message>
+ <message>
+ <source>Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)</source>
+ <translation>Définir le taux minimal de frais (en %s/ko) pour les transactions à inclure dans la création de blocs (par défaut : %s)</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>Définir le nombre de fils de vérification des scripts (%u à %d, 0 = auto, &lt; 0 = laisser ce nombre de cœurs inutilisés, par défaut : %d)</translation>
</message>
@@ -3126,6 +3146,10 @@
<translation>Utiliser l'UPnP pour mapper le port d'écoute (par défaut : 1 en écoute et sans -proxy)</translation>
</message>
<message>
+ <source>Username and hashed password for JSON-RPC connections. The field &lt;userpw&gt; comes in the format: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=&lt;USERNAME&gt;/rpcpassword=&lt;PASSWORD&gt; pair of arguments. This option can be specified multiple times</source>
+ <translation>Nom d'utilisateur et mot de passe haché pour les connexions JSON-RPC. Le champ &lt;userpw&gt; est au format : &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. Un script python canonique est inclus dans share/rpcuser. Le client se connecte ensuite normalement en utilisant la paire d'arguments rpcuser=&lt;USERNAME&gt;/rpcpassword=&lt;PASSWORD&gt;. Cette option peut être spécifiée plusieurs fois.</translation>
+ </message>
+ <message>
<source>Wallet will not create transactions that violate mempool chain limits (default: %u)</source>
<translation>Un porte-monnaie ne créera aucune transaction qui enfreint les limites de chaîne de la réserve de mémoire (par défaut : %u)</translation>
</message>
@@ -3599,7 +3623,7 @@
</message>
<message>
<source>Whether to operate in a blocks only mode (default: %u)</source>
- <translation>Faut-il fonctionner en mode blocs seulement (par défaut : %u)</translation>
+ <translation>Fonctionner ou non en mode blocs seulement (par défaut : %u)</translation>
</message>
<message>
<source>Zapping all transactions from wallet...</source>
@@ -3619,7 +3643,7 @@
</message>
<message>
<source>Allow DNS lookups for -addnode, -seednode and -connect</source>
- <translation>Autoriser les recherches DNS pour -addnode, -seednode et -connect</translation>
+ <translation>Autoriser les consultations DNS pour -addnode, -seednode et -connect</translation>
</message>
<message>
<source>Loading addresses...</source>
@@ -3667,7 +3691,7 @@
</message>
<message>
<source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect/-noconnect)</source>
- <translation>Requête d'adresses de paires par recherche DNS, si il y a peu d'adresses (par défaut : 1 sauf si -connect/-noconnect)</translation>
+ <translation>Requête d'adresses de paires par consultation DNS, si il y a peu d'adresses (par défaut : 1 sauf si -connect/-noconnect)</translation>
</message>
<message>
<source>Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(1) (default: %d)</source>
@@ -3727,7 +3751,7 @@
</message>
<message>
<source>Always query for peer addresses via DNS lookup (default: %u)</source>
- <translation>Toujours demander les adresses des pairs par recherche DNS (par défaut : %u)</translation>
+ <translation>Toujours demander les adresses des pairs par consultation DNS (par défaut : %u)</translation>
</message>
<message>
<source>How many blocks to check at startup (default: %u, 0 = all)</source>
@@ -3771,7 +3795,7 @@
</message>
<message>
<source>Prepend debug output with timestamp (default: %u)</source>
- <translation>Ajouter l'horodatage au début de la sortie de débogage (par défaut : %u)</translation>
+ <translation>Ajouter l'estampille temporelle au début de la sortie de débogage (par défaut : %u)</translation>
</message>
<message>
<source>Relay and mine data carrier transactions (default: %u)</source>
@@ -3783,7 +3807,7 @@
</message>
<message>
<source>Send transactions with full-RBF opt-in enabled (default: %u)</source>
- <translation>Envoyer des transactions avec « RBF opt-in » complet activé (par défaut : %u)</translation>
+ <translation>Envoyer les transactions avec « full-RBF opt-in » activé (par défaut : %u)</translation>
</message>
<message>
<source>Set key pool size to &lt;n&gt; (default: %u)</source>
diff --git a/src/qt/locale/bitcoin_fr_FR.ts b/src/qt/locale/bitcoin_fr_FR.ts
index d53baed462..c10cdf95a2 100644
--- a/src/qt/locale/bitcoin_fr_FR.ts
+++ b/src/qt/locale/bitcoin_fr_FR.ts
@@ -15,7 +15,7 @@
</message>
<message>
<source>Copy the currently selected address to the system clipboard</source>
- <translation>Copier l'adresse surlignée dans votre presse-papiers</translation>
+ <translation>Copier l'adresse sélectionnée dans le presse-papiers</translation>
</message>
<message>
<source>&amp;Copy</source>
@@ -41,10 +41,62 @@
<source>&amp;Delete</source>
<translation>&amp;Supprimer</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Choisissez une adresse où envoyer les bitcoins</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Choisissez une adresse où recevoir les bitcoins</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>C&amp;hoisir</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Adresses d'envoi</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Adresses de réception</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Copier &amp;Étiquette </translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Éditer </translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Exporter la liste d'adresses</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Valeurs séparées par des virgules (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Échec de l'export</translation>
+ </message>
</context>
<context>
<name>AddressTableModel</name>
- </context>
+ <message>
+ <source>Label</source>
+ <translation>Étiquette</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adresse</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(aucune étiquette)</translation>
+ </message>
+</context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -63,6 +115,26 @@
<source>Repeat new passphrase</source>
<translation>Répétez la phrase de passe</translation>
</message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Chiffrer le porte-monnaie</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Déverrouiller le porte-monnaie</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Décrypter le porte-monnaie</translation>
+ </message>
+ <message>
+ <source>Warning: If you encrypt your wallet and lose your passphrase, you will &lt;b&gt;LOSE ALL OF YOUR BITCOINS&lt;/b&gt;!</source>
+ <translation>Attention : Si vous chiffrez votre portefeuille et que vous perdez votre mot de passe vous &lt;b&gt; PERDREZ TOUS VOS BITCOINS&lt;/b&gt; !</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Portefeuille chiffré</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
@@ -79,7 +151,7 @@
<name>BitcoinGUI</name>
<message>
<source>Sign &amp;message...</source>
- <translation>Signer &amp;message...</translation>
+ <translation>Signer un &amp;message...</translation>
</message>
<message>
<source>Synchronizing with network...</source>
@@ -262,10 +334,6 @@
<translation>Indexation des blocs sur le disque...</translation>
</message>
<message>
- <source>No block source available...</source>
- <translation>Aucun bloc source disponible</translation>
- </message>
- <message>
<source>%1 behind</source>
<translation>en retard de %1</translation>
</message>
@@ -368,7 +436,7 @@
</message>
<message>
<source>Fee:</source>
- <translation>Frais:</translation>
+ <translation>Frais :</translation>
</message>
<message>
<source>Dust:</source>
@@ -418,6 +486,50 @@
<source>Confirmed</source>
<translation>Confirmée</translation>
</message>
+ <message>
+ <source>Copy address</source>
+ <translation>Copier l'adresse</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copier l'étiquette</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copier le montant</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Copier l'ID de transaction</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Copier la quantité</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Copier les frais</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Copier après les frais</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Copier les octets</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>oui</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>non</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(aucune étiquette)</translation>
+ </message>
</context>
<context>
<name>EditAddressDialog</name>
@@ -801,6 +913,14 @@
</context>
<context>
<name>QRImageWidget</name>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>&amp;Copier image</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>Sauvegarder QR code</translation>
+ </message>
</context>
<context>
<name>RPCConsole</name>
@@ -1059,7 +1179,15 @@
<source>Remove</source>
<translation>Retirer</translation>
</message>
- </context>
+ <message>
+ <source>Copy label</source>
+ <translation>Copier l'étiquette</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copier le montant</translation>
+ </message>
+</context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -1078,9 +1206,45 @@
<source>&amp;Save Image...</source>
<translation>&amp;Sauvegarder image</translation>
</message>
+ <message>
+ <source>URI</source>
+ <translation>URI</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adresse</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Montant</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Étiquette</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Message</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Date</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Étiquette</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Message</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(aucune étiquette)</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -1184,7 +1348,35 @@
<source>S&amp;end</source>
<translation>E&amp;voyer</translation>
</message>
- </context>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Copier la quantité</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copier le montant</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Copier les frais</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Copier après les frais</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Copier les octets</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>ou</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(aucune étiquette)</translation>
+ </message>
+</context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -1238,7 +1430,11 @@
</context>
<context>
<name>SendConfirmationDialog</name>
- </context>
+ <message>
+ <source>Yes</source>
+ <translation>Oui</translation>
+ </message>
+</context>
<context>
<name>ShutdownWindow</name>
</context>
@@ -1309,7 +1505,87 @@
</context>
<context>
<name>TransactionDesc</name>
- </context>
+ <message>
+ <source>Status</source>
+ <translation>État</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Date</translation>
+ </message>
+ <message>
+ <source>Source</source>
+ <translation>Source</translation>
+ </message>
+ <message>
+ <source>Generated</source>
+ <translation>Généré</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>De</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>inconnu</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation>Á</translation>
+ </message>
+ <message>
+ <source>own address</source>
+ <translation>Votre adresse</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>Lecture uniquement</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>Étiquette </translation>
+ </message>
+ <message>
+ <source>Credit</source>
+ <translation>Crédit</translation>
+ </message>
+ <message>
+ <source>Debit</source>
+ <translation>Débit</translation>
+ </message>
+ <message>
+ <source>Total debit</source>
+ <translation>Débit total</translation>
+ </message>
+ <message>
+ <source>Total credit</source>
+ <translation>Crédit total </translation>
+ </message>
+ <message>
+ <source>Net amount</source>
+ <translation>Montant net</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Message</translation>
+ </message>
+ <message>
+ <source>Comment</source>
+ <translation>Commentaire </translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Montant</translation>
+ </message>
+ <message>
+ <source>true</source>
+ <translation>vrai</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation>faux</translation>
+ </message>
+</context>
<context>
<name>TransactionDescDialog</name>
<message>
@@ -1319,10 +1595,106 @@
</context>
<context>
<name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Date</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Type</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Étiquette</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>Lecture uniquement</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(aucune étiquette)</translation>
+ </message>
</context>
<context>
<name>TransactionView</name>
- </context>
+ <message>
+ <source>All</source>
+ <translation>Toutes</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>Aujourd'hui</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>Cette semaine</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>Ce mois</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>Mois dernier</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>Cette année</translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation>Autres</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Copier l'adresse</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copier l'étiquette</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copier le montant</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Copier l'ID de transaction</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Valeurs séparées par des virgules (*.csv)</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Date</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Type</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Étiquette</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adresse</translation>
+ </message>
+ <message>
+ <source>ID</source>
+ <translation>ID</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Échec de l'export</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>à</translation>
+ </message>
+</context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
diff --git a/src/qt/locale/bitcoin_gl.ts b/src/qt/locale/bitcoin_gl.ts
index 5d31c632ac..ff0804d79b 100644
--- a/src/qt/locale/bitcoin_gl.ts
+++ b/src/qt/locale/bitcoin_gl.ts
@@ -226,10 +226,6 @@
<translation>Opcións da liña de comandos</translation>
</message>
<message>
- <source>No block source available...</source>
- <translation>Non hai orixe de bloques dispoñible...</translation>
- </message>
- <message>
<source>%1 behind</source>
<translation>%1 detrás</translation>
</message>
diff --git a/src/qt/locale/bitcoin_he.ts b/src/qt/locale/bitcoin_he.ts
index 9293b794ad..82be81e921 100644
--- a/src/qt/locale/bitcoin_he.ts
+++ b/src/qt/locale/bitcoin_he.ts
@@ -3,7 +3,7 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation>לחץ מקש ימני כדי לערוך כתובת או תווית</translation>
+ <translation>יש ללחוץ עם הכפתור הימני כדי לערוך כתובת או תווית</translation>
</message>
<message>
<source>Create a new address</source>
@@ -43,15 +43,15 @@
</message>
<message>
<source>Choose the address to send coins to</source>
- <translation>בחר את הכתובת אליה תרצה לשלוח את המטבעות</translation>
+ <translation>נא לבחור את הכתובת אליה ברצונך לשלוח את המטבעות</translation>
</message>
<message>
<source>Choose the address to receive coins with</source>
- <translation>בחר את הכתובת בה תקבל את המטבעות</translation>
+ <translation>נא לבחור את הכתובת לקבלת המטבעות</translation>
</message>
<message>
<source>C&amp;hoose</source>
- <translation>בחר</translation>
+ <translation>&amp;בחירה</translation>
</message>
<message>
<source>Sending addresses</source>
@@ -59,27 +59,35 @@
</message>
<message>
<source>Receiving addresses</source>
- <translation>מקבל כתובות</translation>
+ <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>
+ <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>
+ <translation>אלו הן כתובות הביטקוין שלך לקבלת תשלומים. מומלץ להשתמש בכתובת חדשה לכל העברה.</translation>
</message>
<message>
<source>&amp;Copy Address</source>
- <translation>&amp;העתק כתובת</translation>
+ <translation>ה&amp;עתקת כתובת</translation>
</message>
<message>
<source>Copy &amp;Label</source>
- <translation>העתק &amp;תוית</translation>
+ <translation>העתקת &amp;תוית</translation>
</message>
<message>
<source>&amp;Edit</source>
- <translation>&amp;ערוך</translation>
+ <translation>&amp;עריכה</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>יצוא רשימת הכתובות</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>קובץ מופרד בפסיקים (‎*.csv)</translation>
</message>
<message>
<source>Exporting Failed</source>
@@ -94,7 +102,7 @@
<name>AddressTableModel</name>
<message>
<source>Label</source>
- <translation>תוית</translation>
+ <translation>תווית</translation>
</message>
<message>
<source>Address</source>
@@ -123,10 +131,102 @@
<source>Repeat new passphrase</source>
<translation>נא לחזור על מילת הצופן החדשה</translation>
</message>
- </context>
+ <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>Encrypt wallet</source>
+ <translation>הצפנת הארנק</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>פעולה זו דורשת את מילת הצופן של הארנק שלך כדי לשחרר את הארנק.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>שחרור הארנק</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>פעולה זו דורשת את מילת הצופן של הארנק שלך כדי לפענח את הארנק.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>פענוח הארנק</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>החלפת מילת הצופן</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>נא להזין את מילת הצופן הישנה וחדשה לארנק</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>אימות הצפנת הארנק</translation>
+ </message>
+ <message>
+ <source>Warning: If you encrypt your wallet and lose your passphrase, you will &lt;b&gt;LOSE ALL OF YOUR BITCOINS&lt;/b&gt;!</source>
+ <translation>אזהרה: איבוד מילת הצופן לאחר הצפנת הארנק עשויה לגרום לכך &lt;b&gt;שכל הביטקוינים שלך יאבדו&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>להצפין את הארנק?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>הארנק מוצפן</translation>
+ </message>
+ <message>
+ <source>%1 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>%1 ייסגר כעת כדי לסיים את תהליך ההצפנה. נא לשים לב כי הצפנת הארנק שלך לא יכול להגן על הביטקוינים שלך מפני גניבה או נוזקה שתוקפת את מחשבך.</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>Wallet encryption failed</source>
+ <translation>הצפנת הארנק נכשלה</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>הצפנת הארנק נכשלה עקב תקלה פנימית. הארנק שלך לא הוצפן.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>מילות הצופן שסופקו אינן תואמות.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>שחרור האנרק נכשל</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>מילת הצופן שהוזנה לצורך פענוח הארנק שגויה.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>פענוח הארנק נכשל</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>מילת הצופן של הארנק הוחלפה בהצלחה.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>אזהרה: מקש ה־Caps Lock פעיל!</translation>
+ </message>
+</context>
<context>
<name>BanTableModel</name>
<message>
+ <source>IP/Netmask</source>
+ <translation>IP/מסכת רשת</translation>
+ </message>
+ <message>
<source>Banned Until</source>
<translation>חסום עד</translation>
</message>
@@ -190,6 +290,10 @@
<translation>&amp;אפשרויות…</translation>
</message>
<message>
+ <source>Modify configuration options for %1</source>
+ <translation>שינוי אפשרויות התצורה עבור %1</translation>
+ </message>
+ <message>
<source>&amp;Encrypt Wallet...</source>
<translation>ה&amp;צפנת הארנק…</translation>
</message>
@@ -214,6 +318,22 @@
<translation>פתיחת &amp;כתובת משאב…</translation>
</message>
<message>
+ <source>Click to disable network activity.</source>
+ <translation>יש ללחוץ כדי לנטרל פעילות רשת.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>פעילות הרשת נוטרלה.</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>יש ללחוץ כדי להפעיל את פעילות הרשת מחדש.</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>הכותרות מתעדכנות (%1%)...</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>המקטעים נוספים למפתח בכונן…</translation>
</message>
@@ -313,15 +433,15 @@
<source>&amp;Command-line options</source>
<translation>אפשרויות &amp;שורת הפקודה</translation>
</message>
+ <message numerus="yes">
+ <source>%n active connection(s) to Bitcoin network</source>
+ <translation><numerusform>חיבור אחד פעיל לרשת ביטקוין</numerusform><numerusform>%n חיבורים פעילים לרשת ביטקוין</numerusform></translation>
+ </message>
<message>
<source>Processing blocks on disk...</source>
<translation>מעבד בלוקים על הדיסק...</translation>
</message>
<message>
- <source>No block source available...</source>
- <translation>אין מקור מקטעים זמין…</translation>
- </message>
- <message>
<source>%1 behind</source>
<translation>%1 מאחור</translation>
</message>
@@ -350,10 +470,52 @@
<translation>עדכני</translation>
</message>
<message>
+ <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
+ <translation>יש להציג את הודעת העזרה של %1 כדי להציג רשימה עם אפשרויות שורת פקודה לביטקוין</translation>
+ </message>
+ <message>
+ <source>%1 client</source>
+ <translation>לקוח %1</translation>
+ </message>
+ <message>
+ <source>Connecting to peers...</source>
+ <translation>מתבצעת התחברות לעמיתים…</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<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>
@@ -369,7 +531,11 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>הארנק &lt;b&gt;מוצפן&lt;/b&gt; ו&lt;b&gt;נעול&lt;/b&gt; כרגע</translation>
</message>
- </context>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>אירעה שגיאה חמורה. אין אפשרות להשתמש עוד בביטקוין באופן מאובטח והיישום ייסגר.</translation>
+ </message>
+</context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -441,6 +607,70 @@
<translation>מאושר</translation>
</message>
<message>
+ <source>Copy address</source>
+ <translation>העתקת הכתובת</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>העתקת התווית</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>העתקת הסכום</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>העתקת מזהה ההעברה</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 dust</source>
+ <translation>העתקת אבק</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>העתקת השינוי</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>כן</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>לא</translation>
+ </message>
+ <message>
+ <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
+ <translation>תווית זו הופכת לאדומה אם מישהו מהנמענים מקבל סכום נמוך יותר מסף האבק הנוכחי.</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation>יכול להשתנות במגמה של +/- %1 סנטושי לקלט.</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(ללא תוית)</translation>
</message>
@@ -467,7 +697,39 @@
<source>&amp;Address</source>
<translation>&amp;כתובת</translation>
</message>
- </context>
+ <message>
+ <source>New receiving address</source>
+ <translation>כתובת קבלה חדשה</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>כתובת שליחה חדשה</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>עריכת כתובת הקבלה</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>עריכת כתובת השליחה</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>הכתובת שהוקלדה „%1” היא אינה כתובת ביטקוין תקנית.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book.</source>
+ <translation>הכתובת שהוקלדה „%1” כבר נמצאת בספר הכתובות.</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>לא ניתן לשחרר את הארנק.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>יצירת המפתח החדש נכשלה.</translation>
+ </message>
+</context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -502,6 +764,10 @@
<translation>(%1-סיביות)</translation>
</message>
<message>
+ <source>About %1</source>
+ <translation>על אודות %1</translation>
+ </message>
+ <message>
<source>Command-line options</source>
<translation>אפשרויות שורת פקודה</translation>
</message>
@@ -518,10 +784,22 @@
<translation>אפשרויות ממשק</translation>
</message>
<message>
+ <source>Choose data directory on startup (default: %u)</source>
+ <translation>נא לבחור תיקיית נתונים עם הפתיחה (בררת מחדל: %u)</translation>
+ </message>
+ <message>
+ <source>Set language, for example "de_DE" (default: system locale)</source>
+ <translation>הגדרת השפה, לדוגמה „he_IL” (בררת מחדל: שפת העמרכת)</translation>
+ </message>
+ <message>
<source>Start minimized</source>
<translation>התחל ממוזער</translation>
</message>
<message>
+ <source>Set SSL root certificates for payment request (default: -system-)</source>
+ <translation>הגדרת אישורי בסיס SSL לבקשות תשלומים (בררת מחדל: -מערכת-)</translation>
+ </message>
+ <message>
<source>Show splash screen on startup (default: %u)</source>
<translation>הצג מסך פתיחה בעת הפעלה (ברירת מחדל: %u)</translation>
</message>
@@ -541,6 +819,10 @@
<translation>ברוך הבא ל %1.</translation>
</message>
<message>
+ <source>As this is the first time the program is launched, you can choose where %1 will store its data.</source>
+ <translation>כיוון שזו ההפעלה הראשונה של התכנית, ניתן לבחור היכן יאוחסן המידע של %1.</translation>
+ </message>
+ <message>
<source>Use the default data directory</source>
<translation>שימוש בבררת המחדל של תיקיית הנתונים.</translation>
</message>
@@ -564,14 +846,42 @@
<translation>טופס</translation>
</message>
<message>
+ <source>Number of blocks left</source>
+ <translation>מספר מקטעים שנותרו</translation>
+ </message>
+ <message>
+ <source>Unknown...</source>
+ <translation>לא ידוע...</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation>זמן המקטע האחרון</translation>
</message>
<message>
+ <source>Progress</source>
+ <translation>התקדמות</translation>
+ </message>
+ <message>
+ <source>Progress increase per hour</source>
+ <translation>התקדמות לפי שעה</translation>
+ </message>
+ <message>
+ <source>calculating...</source>
+ <translation>נערך חישוב…</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation>הזמן המוערך שנותר עד הסנכרון</translation>
+ </message>
+ <message>
<source>Hide</source>
<translation>הסתר</translation>
</message>
- </context>
+ <message>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation>לא ידוע. הכותרות מתעדכנות (%1)…</translation>
+ </message>
+</context>
<context>
<name>OpenURIDialog</name>
<message>
@@ -590,7 +900,11 @@
<source>Select payment request file</source>
<translation>בחירת קובץ בקשת תשלום</translation>
</message>
- </context>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>בחירת קובץ בקשת תשלום לפתיחה</translation>
+ </message>
+</context>
<context>
<name>OptionsDialog</name>
<message>
@@ -602,6 +916,14 @@
<translation>&amp;ראשי</translation>
</message>
<message>
+ <source>Automatically start %1 after logging in to the system.</source>
+ <translation>להפעיל את %1 אוטומטית לאחר הכניסה למערכת.</translation>
+ </message>
+ <message>
+ <source>&amp;Start %1 on system login</source>
+ <translation>ה&amp;פעלת %1 עם הכניסה למערכת</translation>
+ </message>
+ <message>
<source>Size of &amp;database cache</source>
<translation>גודל מ&amp;טמון מסד הנתונים</translation>
</message>
@@ -710,6 +1032,14 @@
<translation>&amp;חלון</translation>
</message>
<message>
+ <source>&amp;Hide the icon from the system tray.</source>
+ <translation>ה&amp;סתרת הסמל ממגש המערכת.</translation>
+ </message>
+ <message>
+ <source>Hide tray icon</source>
+ <translation>הסתרת הסמל במגש המערכת</translation>
+ </message>
+ <message>
<source>Show only a tray icon after minimizing the window.</source>
<translation>הצג סמל מגש בלבד לאחר מזעור החלון.</translation>
</message>
@@ -730,6 +1060,10 @@
<translation>&amp;שפת מנשק המשתמש:</translation>
</message>
<message>
+ <source>The user interface language can be set here. This setting will take effect after restarting %1.</source>
+ <translation>ניתן להגדיר כאן את שפת מנשק המשתמש. הגדרה זו תיכנס לתוקף לאחר הפעלה של %1 מחדש.</translation>
+ </message>
+ <message>
<source>&amp;Unit to show amounts in:</source>
<translation>י&amp;חידת מידה להצגת כמויות:</translation>
</message>
@@ -766,6 +1100,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>
@@ -851,7 +1189,71 @@
</context>
<context>
<name>PaymentServer</name>
- </context>
+ <message>
+ <source>Payment request error</source>
+ <translation>שגיאת בקשת תשלום</translation>
+ </message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation>לא ניתן להפעיל את המקשר bitcoin: click-to-pay</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation>טיפול בכתובות</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>Payment request expired.</source>
+ <translation>בקשת התשלום פגה.</translation>
+ </message>
+ <message>
+ <source>Payment request is not initialized.</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>
+ <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>Network request error</source>
+ <translation>שגיאת בקשת רשת</translation>
+ </message>
+ <message>
+ <source>Payment acknowledged</source>
+ <translation>התשלום אושר</translation>
+ </message>
+</context>
<context>
<name>PeerTableModel</name>
<message>
@@ -897,17 +1299,73 @@
<source>%1 ms</source>
<translation>%1 מילישניות</translation>
</message>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation><numerusform>שנייה אחת</numerusform><numerusform>%n שניות</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation><numerusform>דקה אחת</numerusform><numerusform>%n דקות</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation><numerusform>שעה אחת</numerusform><numerusform>%n שעות</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation><numerusform>יום אחד</numerusform><numerusform>%n ימים</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation><numerusform>שבוע אחד</numerusform><numerusform>%n שבועות</numerusform></translation>
+ </message>
<message>
<source>%1 and %2</source>
<translation>%1 ו%2</translation>
</message>
- </context>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation><numerusform>שנה אחת</numerusform><numerusform>%n שנים</numerusform></translation>
+ </message>
+ <message>
+ <source>%1 didn't yet exit safely...</source>
+ <translation>הסגירה של %1 לא הושלמה בהצלחה עדיין…</translation>
+ </message>
+</context>
<context>
<name>QObject::QObject</name>
- </context>
+ <message>
+ <source>Error: Specified data directory "%1" does not exist.</source>
+ <translation>שגיאה: תיקיית הנתונים שצוינה „%1” אינה קיימת.</translation>
+ </message>
+ <message>
+ <source>Error: Cannot parse configuration file: %1. Only use key=value syntax.</source>
+ <translation>שגיאה: לא ניתן לפענח את התצורה: %1. יש להשתמש אך ורק בתחביר מפתח=ערך.</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation>שגיאה: %1</translation>
+ </message>
+</context>
<context>
<name>QRImageWidget</name>
- </context>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;שמירת תמונה…</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>העתקת ת&amp;מונה</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>שמירת קוד QR</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>תמונת PNG (‏‎*.png)</translation>
+ </message>
+</context>
<context>
<name>RPCConsole</name>
<message>
@@ -1011,6 +1469,10 @@
<translation>בלוק התחלה</translation>
</message>
<message>
+ <source>Synced Headers</source>
+ <translation>כותרות עדכניות</translation>
+ </message>
+ <message>
<source>Synced Blocks</source>
<translation>בלוקים מסונכרנים</translation>
</message>
@@ -1111,6 +1573,22 @@
<translation>1 &amp; שנה</translation>
</message>
<message>
+ <source>&amp;Disconnect</source>
+ <translation>&amp;ניתוק</translation>
+ </message>
+ <message>
+ <source>Ban for</source>
+ <translation>חסימה למשך</translation>
+ </message>
+ <message>
+ <source>&amp;Unban</source>
+ <translation>&amp;שחרור חסימה</translation>
+ </message>
+ <message>
+ <source>Welcome to the %1 RPC console.</source>
+ <translation>ברוך בואך למסוף ה־RPC של %1.</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>
@@ -1119,6 +1597,10 @@
<translation>ניתן להקליד &lt;b&gt;help&lt;/b&gt; לקבלת סקירה של הפקודות הזמינות.</translation>
</message>
<message>
+ <source>Network activity disabled</source>
+ <translation>פעילות הרשת נוטרלה</translation>
+ </message>
+ <message>
<source>%1 B</source>
<translation>%1 ב׳</translation>
</message>
@@ -1233,7 +1715,23 @@
<source>Remove</source>
<translation>הסרה</translation>
</message>
- </context>
+ <message>
+ <source>Copy URI</source>
+ <translation>העתקת כתובת</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>העתקת התווית</translation>
+ </message>
+ <message>
+ <source>Copy message</source>
+ <translation>העתקת הודעה</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>העתקת הסכום</translation>
+ </message>
+</context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -1253,24 +1751,64 @@
<translation>&amp;שמירת תמונה…</translation>
</message>
<message>
+ <source>Request payment to %1</source>
+ <translation>בקשת תשלום אל %1</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>פרטי תשלום</translation>
+ </message>
+ <message>
+ <source>URI</source>
+ <translation>כתובת</translation>
+ </message>
+ <message>
<source>Address</source>
<translation>כתובת</translation>
</message>
<message>
+ <source>Amount</source>
+ <translation>סכום</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>תוית</translation>
</message>
+ <message>
+ <source>Message</source>
+ <translation>הודעה</translation>
+ </message>
+ <message>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation>הכתובת שנוצרה ארוכה מדי, כדאי לנסות לקצר את הטקסט של התווית / הודעה.</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
<message>
+ <source>Date</source>
+ <translation>תאריך</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>תוית</translation>
</message>
<message>
+ <source>Message</source>
+ <translation>הודעה</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(ללא תוית)</translation>
</message>
+ <message>
+ <source>(no message)</source>
+ <translation>(אין הודעה)</translation>
+ </message>
+ <message>
+ <source>(no amount requested)</source>
+ <translation>(לא התבקש סכום)</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -1335,6 +1873,10 @@
<translation>בחר...</translation>
</message>
<message>
+ <source>collapse fee-settings</source>
+ <translation>צמצום הגדרות עמלה</translation>
+ </message>
+ <message>
<source>per kilobyte</source>
<translation>עבור קילו-בית</translation>
</message>
@@ -1395,6 +1937,110 @@
<translation>&amp;שליחה</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 dust</source>
+ <translation>העתקת אבק</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>העתקת השינוי</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to send?</source>
+ <translation>לשלוח?</translation>
+ </message>
+ <message>
+ <source>added as transaction fee</source>
+ <translation>נוספה עמלת העברה</translation>
+ </message>
+ <message>
+ <source>Total Amount %1</source>
+ <translation>סכום כולל %1</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>או</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation>אימות שליחת מטבעות</translation>
+ </message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>כתובת הנמען שגויה. נא לבדוק שוב.</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation>הסכום לתשלום צריך להיות גדול מ־0.</translation>
+ </message>
+ <message>
+ <source>The amount exceeds your balance.</source>
+ <translation>הסכום חורג מהמאזן שלך.</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation>נמצאה כתובת כפולה: יש להשתמש בכל כתובת פעם אחת בלבד.</translation>
+ </message>
+ <message>
+ <source>Transaction creation failed!</source>
+ <translation>יצירת ההעברה נכשלה!</translation>
+ </message>
+ <message>
+ <source>The transaction was rejected with the following reason: %1</source>
+ <translation>ההעברה נדחתה מהסיבות הבאות: %1</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>%n block(s)</source>
+ <translation><numerusform>מקטע אחד</numerusform><numerusform>%n מקטעים</numerusform></translation>
+ </message>
+ <message>
+ <source>Pay only the required fee of %1</source>
+ <translation>תשלום של העמלה הנדרשת בלבד על סך %1</translation>
+ </message>
+ <message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>אזהרה: כתובת ביטקיון שגויה</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <translation>אזהרה: כתובת החלפה בלתי ידועה</translation>
+ </message>
+ <message>
+ <source>Confirm custom change address</source>
+ <translation>אימות כתובת החלפה בהתאמה אישית</translation>
+ </message>
+ <message>
+ <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source>
+ <translation>הכתובת שבחרת עבור ההחלפה אינה חלק מארנק זה. כל ההסכום שבארנק שלך עשוי להישלח לכתובת זו. מקובל עליך?</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(ללא תוית)</translation>
</message>
@@ -1442,6 +2088,14 @@
<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;חסרת העמלה מהסכום</translation>
+ </message>
+ <message>
<source>Message:</source>
<translation>הודעה:</translation>
</message>
@@ -1465,10 +2119,18 @@
<source>Memo:</source>
<translation>תזכורת:</translation>
</message>
- </context>
+ <message>
+ <source>Enter a label for this address to add it to your address book</source>
+ <translation>נא להזין תווית לכתובת זו כדי להוסיף אותה לספר הכתובות שלך</translation>
+ </message>
+</context>
<context>
<name>SendConfirmationDialog</name>
- </context>
+ <message>
+ <source>Yes</source>
+ <translation>כן</translation>
+ </message>
+</context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1554,7 +2216,59 @@
<source>Reset all verify message fields</source>
<translation>איפוס כל שדות אימות ההודעה</translation>
</message>
- </context>
+ <message>
+ <source>Click "Sign Message" to generate signature</source>
+ <translation>יש ללחוץ על „חתימת ההודעה“ כדי לייצר חתימה</translation>
+ </message>
+ <message>
+ <source>The entered address is invalid.</source>
+ <translation>הכתובת שהוזנה שגויה.</translation>
+ </message>
+ <message>
+ <source>Please check the address and try again.</source>
+ <translation>נא לבדוק את הכתובת ולנסות שוב.</translation>
+ </message>
+ <message>
+ <source>The entered address does not refer to a key.</source>
+ <translation>הכתובת שהוזנה לא מתייחסת למפתח.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock was cancelled.</source>
+ <translation>שחרור הארנק בוטל.</translation>
+ </message>
+ <message>
+ <source>Private key for the entered address is not available.</source>
+ <translation>המפתח הפרטי לכתובת שהוכנסה אינו זמין.</translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation>חתימת ההודעה נכשלה.</translation>
+ </message>
+ <message>
+ <source>Message signed.</source>
+ <translation>ההודעה נחתמה.</translation>
+ </message>
+ <message>
+ <source>The signature could not be decoded.</source>
+ <translation>לא ניתן לפענח את החתימה.</translation>
+ </message>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation>נא לבדוק את החתימה ולנסות שוב.</translation>
+ </message>
+ <message>
+ <source>The signature did not match the message digest.</source>
+ <translation>החתימה לא תואמת את תקציר ההודעה.</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation>וידוא ההודעה נכשל.</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation>ההודעה עברה וידוא.</translation>
+ </message>
+</context>
<context>
<name>SplashScreen</name>
<message>
@@ -1571,28 +2285,304 @@
</context>
<context>
<name>TransactionDesc</name>
- </context>
+ <message>
+ <source>in memory pool</source>
+ <translation>במאגר הזיכרון</translation>
+ </message>
+ <message>
+ <source>not in memory pool</source>
+ <translation>לא במאגר הזיכרון</translation>
+ </message>
+ <message>
+ <source>abandoned</source>
+ <translation>ננטש</translation>
+ </message>
+ <message>
+ <source>Status</source>
+ <translation>מצב</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>תאריך</translation>
+ </message>
+ <message>
+ <source>Source</source>
+ <translation>מקור</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>מאת</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>לא ידוע</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation>אל</translation>
+ </message>
+ <message>
+ <source>own address</source>
+ <translation>כתובת עצמית</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>צפייה בלבד</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>תווית</translation>
+ </message>
+ <message>
+ <source>Credit</source>
+ <translation>אשראי</translation>
+ </message>
+ <message>
+ <source>Debit</source>
+ <translation>חיוב</translation>
+ </message>
+ <message>
+ <source>Total debit</source>
+ <translation>חיוב כולל</translation>
+ </message>
+ <message>
+ <source>Total credit</source>
+ <translation>אשראי כול</translation>
+ </message>
+ <message>
+ <source>Transaction fee</source>
+ <translation>עמלת העברה</translation>
+ </message>
+ <message>
+ <source>Net amount</source>
+ <translation>סכום נטו</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>הודעה</translation>
+ </message>
+ <message>
+ <source>Comment</source>
+ <translation>הערה</translation>
+ </message>
+ <message>
+ <source>Transaction ID</source>
+ <translation>מזהה העברה</translation>
+ </message>
+ <message>
+ <source>Transaction total size</source>
+ <translation>גודל ההעברה הכללי</translation>
+ </message>
+ <message>
+ <source>Output index</source>
+ <translation>מפתח פלט</translation>
+ </message>
+ <message>
+ <source>Debug information</source>
+ <translation>פרטי ניפוי שגיאות</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation>העברה</translation>
+ </message>
+ <message>
+ <source>Inputs</source>
+ <translation>אמצעי קלט</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>סכום</translation>
+ </message>
+ <message>
+ <source>true</source>
+ <translation>אמת</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation>שקר</translation>
+ </message>
+</context>
<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>חלונית זו מציגה תיאור מפורט של ההעברה</translation>
</message>
- </context>
+ <message>
+ <source>Details for %1</source>
+ <translation>פרטים עבור %1</translation>
+ </message>
+</context>
<context>
<name>TransactionTableModel</name>
<message>
+ <source>Date</source>
+ <translation>תאריך</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>סוג</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>תוית</translation>
</message>
<message>
+ <source>Abandoned</source>
+ <translation>ננטש</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>התקבל עם</translation>
+ </message>
+ <message>
+ <source>Received from</source>
+ <translation>התקבל מאת</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>נשלח אל</translation>
+ </message>
+ <message>
+ <source>Payment to yourself</source>
+ <translation>תשלום לעצמך</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>נכרו</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>צפייה בלבד</translation>
+ </message>
+ <message>
+ <source>(n/a)</source>
+ <translation>(לא זמין)</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(ללא תוית)</translation>
</message>
+ <message>
+ <source>Type of transaction.</source>
+ <translation>סוג ההעברה.</translation>
+ </message>
</context>
<context>
<name>TransactionView</name>
<message>
+ <source>All</source>
+ <translation>הכול</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>היום</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>השבוע</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>החודש</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>חודש שעבר</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>השנה הזאת</translation>
+ </message>
+ <message>
+ <source>Range...</source>
+ <translation>טווח…</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>התקבל עם</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>נשלח אל</translation>
+ </message>
+ <message>
+ <source>To yourself</source>
+ <translation>לעצמך</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>נכרו</translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation>אחר</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation>נא להזין כתובת או תווית לחיפוש</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation>סכום מזערי</translation>
+ </message>
+ <message>
+ <source>Abandon transaction</source>
+ <translation>נטישת העברה</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>העתקת הכתובת</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>העתקת התווית</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>העתקת הסכום</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>העתקת מזהה ההעברה</translation>
+ </message>
+ <message>
+ <source>Copy raw transaction</source>
+ <translation>העתקת העברה גולמית</translation>
+ </message>
+ <message>
+ <source>Copy full transaction details</source>
+ <translation>העתקת פרטי ההעברה המלאים</translation>
+ </message>
+ <message>
+ <source>Edit label</source>
+ <translation>עריכת תווית</translation>
+ </message>
+ <message>
+ <source>Show transaction details</source>
+ <translation>הצגת פרטי העברה</translation>
+ </message>
+ <message>
+ <source>Export Transaction History</source>
+ <translation>יצוא היסטוריית העברה</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>קובץ מופרד בפסיקים (‎*.csv)</translation>
+ </message>
+ <message>
+ <source>Watch-only</source>
+ <translation>צפייה בלבד</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>תאריך</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>סוג</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>תוית</translation>
</message>
@@ -1601,10 +2591,34 @@
<translation>כתובת</translation>
</message>
<message>
+ <source>ID</source>
+ <translation>מזהה</translation>
+ </message>
+ <message>
<source>Exporting Failed</source>
<translation>יצוא נכשל</translation>
</message>
- </context>
+ <message>
+ <source>There was an error trying to save the transaction history to %1.</source>
+ <translation>אירעה שגיאה בעת ניסיון שמירת היסטוריית ההעברות אל %1.</translation>
+ </message>
+ <message>
+ <source>Exporting Successful</source>
+ <translation>הייצוא נכשל</translation>
+ </message>
+ <message>
+ <source>The transaction history was successfully saved to %1.</source>
+ <translation>היסטוריית ההעברות נשמרה בהצלחה אל %1.</translation>
+ </message>
+ <message>
+ <source>Range:</source>
+ <translation>טווח:</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>עד</translation>
+ </message>
+</context>
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
@@ -1614,13 +2628,53 @@
</context>
<context>
<name>WalletFrame</name>
- </context>
+ <message>
+ <source>No wallet has been loaded.</source>
+ <translation>לא נטען ארנק.</translation>
+ </message>
+</context>
<context>
<name>WalletModel</name>
- </context>
+ <message>
+ <source>Send Coins</source>
+ <translation>שליחת מטבעות</translation>
+ </message>
+</context>
<context>
<name>WalletView</name>
- </context>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;יצוא</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>יצוא הנתונים בלשונית הנוכחית לקובץ</translation>
+ </message>
+ <message>
+ <source>Backup Wallet</source>
+ <translation>גיבוי הארנק</translation>
+ </message>
+ <message>
+ <source>Wallet Data (*.dat)</source>
+ <translation>נתוני ארנק (‎*.dat)</translation>
+ </message>
+ <message>
+ <source>Backup Failed</source>
+ <translation>הגיבוי נכשל</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the wallet data to %1.</source>
+ <translation>אירעה שגיאה בעת הניסיון לשמור את נתוני הארנק אל %1.</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation>הגיבוי הצליח</translation>
+ </message>
+ <message>
+ <source>The wallet data was successfully saved to %1.</source>
+ <translation>נתוני הארנק נשמרו בהצלחה אל %1.</translation>
+ </message>
+</context>
<context>
<name>bitcoin-core</name>
<message>
@@ -1644,6 +2698,10 @@
<translation>קבלת פקודות משורת הפקודה ומ־JSON-RPC</translation>
</message>
<message>
+ <source>Accept connections from outside (default: 1 if no -proxy or -connect/-noconnect)</source>
+ <translation>קבלת חיבורים מבחוץ (בררת מחדל: 1 אם לא במצב ‎-proxy או ‎-connect/-noconnet)</translation>
+ </message>
+ <message>
<source>Error: A fatal internal error occurred, see debug.log for details</source>
<translation>שגיאה: סניה קלמה קריטית פנימית קרטה, פנה ל debug.log לפרטים</translation>
</message>
@@ -1672,14 +2730,38 @@
<translation>ביצוע פקודה כאשר העברה בארנק משתנה (%s ב־cmd יוחלף ב־TxID)</translation>
</message>
<message>
+ <source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source>
+ <translation>שימוש ב־UPnP כדי למפות את הפתחה להאזנה (בררת מחדל: 1 בעת האזנה ובלי ‎-proxy)</translation>
+ </message>
+ <message>
+ <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
+ <translation>אזהרה: נראה כי הרשת אינה מסכימה באופן מלא! חלק מהכורים חווים תקלות.</translation>
+ </message>
+ <message>
+ <source>You need to rebuild the database using -reindex-chainstate to change -txindex</source>
+ <translation>עליך לבנות מחדש את מסד הנתונים בעזרת ‎-reindex-chainstate כדי לשנות את ‎-txindex</translation>
+ </message>
+ <message>
+ <source>-maxmempool must be at least %d MB</source>
+ <translation>‎-maxmempool חייב להיות לפחות %d מ״ב</translation>
+ </message>
+ <message>
<source>&lt;category&gt; can be:</source>
<translation>&lt;קטגוריה&gt; יכולה להיות:</translation>
</message>
<message>
+ <source>Append comment to the user agent string</source>
+ <translation>הוספת הערה למחרוזת סוכן המשתמש</translation>
+ </message>
+ <message>
<source>Block creation options:</source>
<translation>אפשרויות יצירת מקטע:</translation>
</message>
<message>
+ <source>Chain selection options:</source>
+ <translation>אפשרויות בחירת שרשרת:</translation>
+ </message>
+ <message>
<source>Change index out of range</source>
<translation>אינדקס העודף מחוץ לתחום</translation>
</message>
@@ -1688,6 +2770,10 @@
<translation>הגדרות חיבור:</translation>
</message>
<message>
+ <source>Copyright (C) %i-%i</source>
+ <translation>כל הזכויות שמורות (C) %i-‏%i</translation>
+ </message>
+ <message>
<source>Corrupted block database detected</source>
<translation>התגלה מסד נתוני מקטעים לא תקין</translation>
</message>
@@ -1744,6 +2830,14 @@
<translation>כתובת onion- שגויה: '%s'</translation>
</message>
<message>
+ <source>Invalid amount for -%s=&lt;amount&gt;: '%s'</source>
+ <translation>סכום שגוי עבור ‎-%s=&lt;amount&gt;:‏ '%s'</translation>
+ </message>
+ <message>
+ <source>Invalid amount for -fallbackfee=&lt;amount&gt;: '%s'</source>
+ <translation>סכום שגוי עבור ‎-fallbackfee=&lt;amount&gt;:‏ '%s'</translation>
+ </message>
+ <message>
<source>Loading banlist...</source>
<translation>טוען רשימת חסומים...</translation>
</message>
@@ -1756,6 +2850,10 @@
<translation>תמיד להתחבר למפרקים ברשת &lt;net&gt;‏ (ipv4,‏ ipv6 או onion)</translation>
</message>
<message>
+ <source>Print this help message and exit</source>
+ <translation>להדפיס הודעת עזרה זו ולצאת</translation>
+ </message>
+ <message>
<source>Print version and exit</source>
<translation>הדפס גירסא וצא</translation>
</message>
@@ -1788,6 +2886,10 @@
<translation>אפשרות דיבוג/בדיקת ארנק:</translation>
</message>
<message>
+ <source>Wallet needed to be rewritten: restart %s to complete</source>
+ <translation>יש לכתוב את הארנק מחדש: יש להפעיל את %s כדי להמשיך</translation>
+ </message>
+ <message>
<source>Wallet options:</source>
<translation>אפשרויות הארנק:</translation>
</message>
@@ -1800,6 +2902,10 @@
<translation>סכום העברה נמוך מדי לשליחה אחרי גביית העמלה</translation>
</message>
<message>
+ <source>(default: %u)</source>
+ <translation>(בררת מחדל: %u)</translation>
+ </message>
+ <message>
<source>Connect through SOCKS5 proxy</source>
<translation>התחברות דרך מתווך SOCKS5</translation>
</message>
@@ -1896,14 +3002,90 @@
<translation>הכתובות בטעינה…</translation>
</message>
<message>
+ <source>Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.</source>
+ <translation>המשתנה ‎-socks נמצא אך אין בו תמיכה עוד. הגדרת גרסת SOCKS אינה אפשרית עוד, קיימת תמיכה רק ב־SOCKS5.</translation>
+ </message>
+ <message>
<source>(default: %s)</source>
<translation>(ברירת מחדל: %s)</translation>
</message>
<message>
+ <source>Always query for peer addresses via DNS lookup (default: %u)</source>
+ <translation>תמיד לתשאל את כתובת העמיתים באמצעות חיפוש DNS (בררת מחדל: %u)</translation>
+ </message>
+ <message>
+ <source>How many blocks to check at startup (default: %u, 0 = all)</source>
+ <translation>כמה מקטעים לבדוק עם ההפעלה (בררת מחדל: %u,‏ 0 = הכול)</translation>
+ </message>
+ <message>
+ <source>Include IP addresses in debug output (default: %u)</source>
+ <translation>לכלול את כתובת ה־IP בפלט ניפוי השגיאות (בררת מחדל: %u)</translation>
+ </message>
+ <message>
<source>Invalid -proxy address: '%s'</source>
<translation>כתובת ‎-proxy לא תקינה: '%s'</translation>
</message>
<message>
+ <source>Listen for JSON-RPC connections on &lt;port&gt; (default: %u or testnet: %u)</source>
+ <translation>האזנה לחיבורי JSON-RPC דרך &lt;port&gt; (בררת מחדל: %u או ברשת הבדיקה: %u)</translation>
+ </message>
+ <message>
+ <source>Listen for connections on &lt;port&gt; (default: %u or testnet: %u)</source>
+ <translation>האזנה לחיבורים על גבי &lt;port&gt; (בררת מחדל: %u או לרשת הבדיקה: %u)</translation>
+ </message>
+ <message>
+ <source>Maintain at most &lt;n&gt; connections to peers (default: %u)</source>
+ <translation>לשמור על &lt;n&gt; חיבורים לעמיתים לכל היותר (בררת מחדל: %u)</translation>
+ </message>
+ <message>
+ <source>Make the wallet broadcast transactions</source>
+ <translation>להגדיר את הארנק להפצת העברות</translation>
+ </message>
+ <message>
+ <source>Set key pool size to &lt;n&gt; (default: %u)</source>
+ <translation>הגדרת גודל מאגר המפתחות לכדי &lt;n&gt; (בררת מחדל: %u)</translation>
+ </message>
+ <message>
+ <source>Set maximum BIP141 block weight (default: %d)</source>
+ <translation>הגדרת משקל מרבי למקטע BIP141 (בררת מחדל: %d)</translation>
+ </message>
+ <message>
+ <source>Specify configuration file (default: %s)</source>
+ <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>Starting network threads...</source>
+ <translation>תהליכי הרשת מופעלים…</translation>
+ </message>
+ <message>
+ <source>This is the minimum transaction fee you pay on every transaction.</source>
+ <translation>זו עמלת ההעברה המזערית שתיגבה מכל העברה שלך.</translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you will pay if you send a transaction.</source>
+ <translation>זו עמלת ההעברה שתיגבה ממך במידה של שליחת העברה.</translation>
+ </message>
+ <message>
+ <source>Threshold for disconnecting misbehaving peers (default: %u)</source>
+ <translation>סף לניתוק עמיתים סוררים (בררת מחדל: %u)</translation>
+ </message>
+ <message>
+ <source>Transaction amounts must not be negative</source>
+ <translation>סכומי ההעברה לא יכולים להיות שליליים</translation>
+ </message>
+ <message>
+ <source>Transaction must have at least one recipient</source>
+ <translation>להעברה חייב להיות לפחות נמען אחד</translation>
+ </message>
+ <message>
<source>Unknown network specified in -onlynet: '%s'</source>
<translation>רשת לא ידועה צוינה דרך ‎-onlynet:‏ '%s'</translation>
</message>
diff --git a/src/qt/locale/bitcoin_hi_IN.ts b/src/qt/locale/bitcoin_hi_IN.ts
index 20fbd0e0ae..e1db9c2529 100644
--- a/src/qt/locale/bitcoin_hi_IN.ts
+++ b/src/qt/locale/bitcoin_hi_IN.ts
@@ -2,14 +2,26 @@
<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>
<message>
+ <source>&amp;New</source>
+ <translation>नया</translation>
+ </message>
+ <message>
<source>Copy the currently selected address to the system clipboard</source>
<translation>चुनिन्दा पते को सिस्टम क्लिपबोर्ड पर कापी करे !</translation>
</message>
<message>
+ <source>Delete the currently selected address from the list</source>
+ <translation>सूची से वर्तमान में चयनित पता हटाएं</translation>
+ </message>
+ <message>
<source>&amp;Delete</source>
<translation>&amp;मिटाए !!</translation>
</message>
diff --git a/src/qt/locale/bitcoin_hu.ts b/src/qt/locale/bitcoin_hu.ts
index 49b9dc7d1c..5c98319c6b 100644
--- a/src/qt/locale/bitcoin_hu.ts
+++ b/src/qt/locale/bitcoin_hu.ts
@@ -41,9 +41,17 @@
<source>&amp;Delete</source>
<translation>&amp;Törlés</translation>
</message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Cím másolása</translation>
+ </message>
</context>
<context>
<name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Címke</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -63,6 +71,10 @@
<source>Repeat new passphrase</source>
<translation>Új jelszó újra</translation>
</message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Tárca dekódolása</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
@@ -257,10 +269,6 @@
<source>%n active connection(s) to Bitcoin network</source>
<translation><numerusform>%n aktív kapcsolat a Bitcoin hálózathoz</numerusform><numerusform>%n aktív kapcsolat a Bitcoin hálózathoz</numerusform></translation>
</message>
- <message>
- <source>No block source available...</source>
- <translation>Blokk forrása ismeretlen...</translation>
- </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation><numerusform>%n blokk feldolgozva a tranzakció előzményből.</numerusform><numerusform>%n blokk feldolgozva a tranzakció előzményből.</numerusform></translation>
@@ -1082,9 +1090,17 @@
<source>&amp;Save Image...</source>
<translation>&amp;Kép mentése</translation>
</message>
+ <message>
+ <source>Label</source>
+ <translation>Címke</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Címke</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -1335,9 +1351,17 @@
</context>
<context>
<name>TransactionTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Címke</translation>
+ </message>
</context>
<context>
<name>TransactionView</name>
+ <message>
+ <source>Label</source>
+ <translation>Címke</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
diff --git a/src/qt/locale/bitcoin_id_ID.ts b/src/qt/locale/bitcoin_id_ID.ts
index 5cc5d71c6d..89ec216ab3 100644
--- a/src/qt/locale/bitcoin_id_ID.ts
+++ b/src/qt/locale/bitcoin_id_ID.ts
@@ -41,10 +41,74 @@
<source>&amp;Delete</source>
<translation>&amp;Hapus</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Pilih alamat untuk mengirim koin</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Piih alamat untuk menerima koin</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>&amp;Pilih</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Alamat-alamat pengirim</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Alamat-alamat penerima</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>Ini adalah alamat- alamat Bitcoin Anda untuk mengirimkan pembayaran. Selalu periksa jumlah dan alamat penerima sebelum mengirimkan koin.</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>Ini adalah alamat- alamat Bitcoin Anda untuk menerima pembayaran. Dianjurkan untuk menggunakan alamat penerima yang baru setiap melakukan transaksi.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Salin Alamat</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Salin&amp; Label</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Ubah</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Ekspor Daftar Alamat</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>File yang berformat(*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Mengekspor Gagal</translation>
+ </message>
</context>
<context>
<name>AddressTableModel</name>
- </context>
+ <message>
+ <source>Label</source>
+ <translation>Label</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Alamat</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(tidak ada label)</translation>
+ </message>
+</context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -63,7 +127,95 @@
<source>Repeat new passphrase</source>
<translation>Ulangi kata kunci baru</translation>
</message>
- </context>
+ <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>Masukan kata sandi baru ke dompet.&lt;br/&gt;Mohon gunakan kata sandi &lt;b&gt;sepuluh karakter acak atau lebih&lt;/b&gt;, atau &lt;b&gt; delapan atau lebih beberapa kata &lt;/​​b&gt;.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Enkripsi dompet</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Operasi ini memerlukan kata sandi dompet Anda untuk membuka dompet.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Buka dompet</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Operasi ini memerlukan kata sandi dompet Anda untuk mendekripsikan dompet.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Dekripsi dompet</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Ganti kata sandi</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Masukkan kata sandi lama dan kata sandi baru ke dompet.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Konfirmasi pengenkripsian dompet</translation>
+ </message>
+ <message>
+ <source>Warning: If you encrypt your wallet and lose your passphrase, you will &lt;b&gt;LOSE ALL OF YOUR BITCOINS&lt;/b&gt;!</source>
+ <translation>Peringatan: Jika Anda enkripsi dompet Anda dan lupa kata sandi anda, Anda akan &lt;b&gt;KEHILANGAN SEMUA BITCOIN ANDA&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Apakah Anda yakin ingin enkripsi dompet Anda?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Dompet terenkripsi</translation>
+ </message>
+ <message>
+ <source>%1 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>%1 sekarang akan ditutup untuk menyelesaikan proses enkripsi. Ingatlah bahwa mengenkripsi dompet Anda tidak dapat sepenuhnya melindungi komputer Anda dari pencurian malware yang menginfeksi komputer Anda.</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>PENTING: Backup sebelumnya yang Anda buat dari file dompet Anda harus diganti dengan file dompet terenkripsi yang baru dibuat. Demi keamanan, backup file dompet sebelumnya yang tidak dienkripsi sebelumnya akan menjadi tidak berguna begitu Anda mulai menggunakan dompet terenkripsi yang baru.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Pengenkripsian dompet gagal</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Pengenkripsian dompet gagal karena kesalahan internal. Dompet Anda tidak dienkripsi.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>Kata sandi yang dimasukkan tidak cocok.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Membuka dompet gagal</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>Kata sandi yang dimasukkan untuk dekripsi dompet salah.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Dekripsi dompet gagal</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>Kata sandi berhasil diganti.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Peringatan: Tombol Caps Lock aktif!</translation>
+ </message>
+</context>
<context>
<name>BanTableModel</name>
<message>
@@ -114,6 +266,14 @@
<translation>Keluar dari aplikasi</translation>
</message>
<message>
+ <source>&amp;About %1</source>
+ <translation>&amp;Tentang%1</translation>
+ </message>
+ <message>
+ <source>Show information about %1</source>
+ <translation>Tampilkan informasi perihal %1</translation>
+ </message>
+ <message>
<source>About &amp;Qt</source>
<translation>Mengenai &amp;Qt</translation>
</message>
@@ -126,6 +286,10 @@
<translation>&amp;Pilihan...</translation>
</message>
<message>
+ <source>Modify configuration options for %1</source>
+ <translation>Pengubahan opsi konfigurasi untuk %1</translation>
+ </message>
+ <message>
<source>&amp;Encrypt Wallet...</source>
<translation>&amp;Enkripsi Dompet...</translation>
</message>
@@ -150,6 +314,22 @@
<translation>Buka &amp;URI</translation>
</message>
<message>
+ <source>Click to disable network activity.</source>
+ <translation>Klik untuk menonaktifkan aktivitas jaringan.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>Aktivitas jaringan dinonaktifkan.</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>Klik untuk mengaktifkan aktivitas jaringan lagi.</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>Menyinkronkan Header (%1%) ...</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>Mengindex ulang blok di dalam disk...</translation>
</message>
@@ -254,8 +434,12 @@
<translation><numerusform>%n koneksi aktif ke jaringan Bitcoin</numerusform></translation>
</message>
<message>
- <source>No block source available...</source>
- <translation>Sumber blok tidak tersedia...</translation>
+ <source>Indexing blocks on disk...</source>
+ <translation>Pengindeksan blok pada disk ...</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk...</source>
+ <translation>Memproses blok pada disk ...</translation>
</message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
@@ -290,6 +474,18 @@
<translation>Terbaru</translation>
</message>
<message>
+ <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
+ <translation>Tampilkan %1 pesan bantuan untuk mendapatkan daftar opsi baris perintah Bitcoin yang memungkinkan</translation>
+ </message>
+ <message>
+ <source>%1 client</source>
+ <translation>%1 klien</translation>
+ </message>
+ <message>
+ <source>Connecting to peers...</source>
+ <translation>Menghubungkan ke peer...</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>Menyusul...</translation>
</message>
@@ -332,6 +528,14 @@
<translation>Transaksi diterima</translation>
</message>
<message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation>Pembuatan kunci HD &lt;b&gt;diaktifkan&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation>Pembuatan kunci HD &lt;b&gt;dinonaktifkan&lt;/b&gt;</translation>
+ </message>
+ <message>
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
<translation>Dompet saat ini &lt;b&gt;terenkripsi&lt;/b&gt; dan &lt;b&gt;terbuka&lt;/b&gt;</translation>
</message>
@@ -339,7 +543,11 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Dompet saat ini &lt;b&gt;terenkripsi&lt;/b&gt; dan &lt;b&gt;terkunci&lt;/b&gt;</translation>
</message>
- </context>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>Terjadi Kesalahan Fatal. Bitcoin Tidak Dapat Melanjutkan Dengan Aman Dan Akan Keluar</translation>
+ </message>
+</context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -410,6 +618,70 @@
<source>Confirmed</source>
<translation>Terkonfirmasi</translation>
</message>
+ <message>
+ <source>Copy address</source>
+ <translation>Salin alamat</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Salin label</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Salin Jumlah</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Salain ID Transaksi</translation>
+ </message>
+ <message>
+ <source>Lock unspent</source>
+ <translation>Kunci Yang Tidak Digunakan</translation>
+ </message>
+ <message>
+ <source>Unlock unspent</source>
+ <translation>Buka Kunci Yang Tidak Digunakan</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Salin Kuantitas</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Salin biaya</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Salin Setelah Upah</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Salin bytes</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Salin jumlah yang lebih kecil</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Salin Perubahan</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation>(%1 terkunci)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>Ya</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>Tidak</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(tidak ada label)</translation>
+ </message>
</context>
<context>
<name>EditAddressDialog</name>
@@ -433,7 +705,39 @@
<source>&amp;Address</source>
<translation>&amp;Alamat</translation>
</message>
- </context>
+ <message>
+ <source>New receiving address</source>
+ <translation>Alamat penerima baru</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Alamat pengirim baru</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Ubah alamat penerima</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Ubah alamat pengirim</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>Alamat yang dimasukkan "%1" bukanlah alamat Bitcoin yang valid.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book.</source>
+ <translation>Alamat yang dimasukkan "%1" sudah ada di dalam buku alamat.</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Tidak dapat membuka dompet.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Pembuatan kunci baru gagal.</translation>
+ </message>
+</context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -468,6 +772,10 @@
<translation>(%1-bit)</translation>
</message>
<message>
+ <source>About %1</source>
+ <translation>Tentang %1</translation>
+ </message>
+ <message>
<source>Command-line options</source>
<translation>Pilihan Command-line</translation>
</message>
@@ -503,7 +811,11 @@
<source>Show splash screen on startup (default: %u)</source>
<translation>Tampilkan layar kilat saat memulai (default: %u)</translation>
</message>
- </context>
+ <message>
+ <source>Reset all settings changed in the GUI</source>
+ <translation>Hapus semua pengaturan pada GUI.</translation>
+ </message>
+</context>
<context>
<name>Intro</name>
<message>
@@ -511,6 +823,14 @@
<translation>Selamat Datang</translation>
</message>
<message>
+ <source>Welcome to %1.</source>
+ <translation>Selamat Datang ke %1.</translation>
+ </message>
+ <message>
+ <source>As this is the first time the program is launched, you can choose where %1 will store its data.</source>
+ <translation>Karena ini adalah pertama kalinya program dijalankan, Anda dapat memilih lokasi %1 akan menyimpan data.</translation>
+ </message>
+ <message>
<source>Use the default data directory</source>
<translation>Gunakan direktori data default.</translation>
</message>
@@ -1069,7 +1389,15 @@
<source>Remove</source>
<translation>Menghapus</translation>
</message>
- </context>
+ <message>
+ <source>Copy label</source>
+ <translation>Salin label</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Salin Jumlah</translation>
+ </message>
+</context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -1089,12 +1417,28 @@
<translation>&amp;Simpan Gambaran...</translation>
</message>
<message>
+ <source>Address</source>
+ <translation>Alamat</translation>
+ </message>
+ <message>
<source>Amount</source>
<translation>Jumlah</translation>
</message>
+ <message>
+ <source>Label</source>
+ <translation>Label</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Label</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(tidak ada label)</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -1198,7 +1542,39 @@
<source>S&amp;end</source>
<translation>K&amp;irim</translation>
</message>
- </context>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Salin Kuantitas</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Salin Jumlah</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Salin biaya</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Salin Setelah Upah</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Salin bytes</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Salin dust</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Salin Perubahan</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(tidak ada label)</translation>
+ </message>
+</context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -1361,9 +1737,49 @@
</context>
<context>
<name>TransactionTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Label</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(tidak ada label)</translation>
+ </message>
</context>
<context>
<name>TransactionView</name>
+ <message>
+ <source>Copy address</source>
+ <translation>Salin alamat</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Salin label</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Salin Jumlah</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Salain ID Transaksi</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Berkas yang berformat(*.csv)</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Label</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Alamat</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Mengekspor Gagal</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
diff --git a/src/qt/locale/bitcoin_it.ts b/src/qt/locale/bitcoin_it.ts
index 76cfdfafa5..d38459c6ff 100644
--- a/src/qt/locale/bitcoin_it.ts
+++ b/src/qt/locale/bitcoin_it.ts
@@ -3,7 +3,7 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation>Fare clic con il tasto destro del mouse per modificare l'indirizzo o l'etichettadefault</translation>
+ <translation>Tasto destro per modificare l'indirizzo o l'etichetta</translation>
</message>
<message>
<source>Create a new address</source>
@@ -180,10 +180,22 @@
<translation>Portamonete cifrato</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>
+ <message>
<source>Wallet encryption failed</source>
<translation>Il processo di crittografia del tuo portafogli è fallito</translation>
</message>
<message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Crittaggio fallito a causa di un errore interno. Il portamonete non è stato crittato.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>Le frasi di accesso non corrispondono.</translation>
+ </message>
+ <message>
<source>Wallet unlock failed</source>
<translation>Sbloccaggio del portafoglio fallito</translation>
</message>
@@ -191,7 +203,19 @@
<source>The passphrase entered for the wallet decryption was incorrect.</source>
<translation>La frase inserita per decrittografare il tuo portafoglio è incorretta</translation>
</message>
- </context>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Decrittazione del portamonete fallita.</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>La frase di accesso al portamonete è stata cambiata con successo.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Attenzione: è attivo il tasto blocco maiuscole !</translation>
+ </message>
+</context>
<context>
<name>BanTableModel</name>
<message>
@@ -290,6 +314,22 @@
<translation>Apri &amp;URI...</translation>
</message>
<message>
+ <source>Click to disable network activity.</source>
+ <translation>Clicca per disattivare la rete.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>Attività di rete disabilitata</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>Clicca per abilitare nuovamente l'attività di rete</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>Sincronizzazione Headers (%1%)...</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>Re-indicizzazione blocchi su disco...</translation>
</message>
@@ -401,10 +441,6 @@
<source>Processing blocks on disk...</source>
<translation>Processando i blocchi su disco...</translation>
</message>
- <message>
- <source>No block source available...</source>
- <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>
@@ -446,6 +482,10 @@
<translation>%1 client</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>Connessione ai peers</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>In aggiornamento...</translation>
</message>
@@ -488,6 +528,14 @@
<translation>Transazione ricevuta</translation>
</message>
<message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation>La creazione della chiave HD è &lt;b&gt;abilitata&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation>La creazione della chiave HD è &lt;b&gt;disabilitata&lt;/b&gt;</translation>
+ </message>
+ <message>
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
<translation>Il portamonete è &lt;b&gt;cifrato&lt;/b&gt; ed attualmente &lt;b&gt;sbloccato&lt;/b&gt;</translation>
</message>
@@ -495,7 +543,11 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Il portamonete è &lt;b&gt;cifrato&lt;/b&gt; ed attualmente &lt;b&gt;bloccato&lt;/b&gt;</translation>
</message>
- </context>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>Si è verificato un errore critico. Bitcoin non può più funzionare in maniera sicura e verrà chiuso.</translation>
+ </message>
+</context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -567,10 +619,86 @@
<translation>Confermato</translation>
</message>
<message>
+ <source>Copy address</source>
+ <translation>Copia indirizzo</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copia etichetta</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copia l'importo</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Copia l'ID transazione</translation>
+ </message>
+ <message>
+ <source>Lock unspent</source>
+ <translation>Bloccare non spesi</translation>
+ </message>
+ <message>
+ <source>Unlock unspent</source>
+ <translation>Sbloccare non spesi</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Copia quantità</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Copia commissione</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Copia dopo commissione</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Copia byte</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Copia trascurabile</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Copia resto</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation>(%1 bloccato)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>sì</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>no</translation>
+ </message>
+ <message>
+ <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
+ <translation>Questa etichetta diventerà rossa se uno qualsiasi dei destinatari riceverà un importo inferiore alla corrente soglia minima per la movimentazione della valuta.</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation>Può variare di +/- %1 satoshi per input.</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(nessuna etichetta)</translation>
</message>
- </context>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation>cambio da %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(resto)</translation>
+ </message>
+</context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -593,7 +721,39 @@
<source>&amp;Address</source>
<translation>&amp;Indirizzo</translation>
</message>
- </context>
+ <message>
+ <source>New receiving address</source>
+ <translation>Nuovo indirizzo di ricezione</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Nuovo indirizzo d'invio</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Modifica indirizzo di ricezione</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Modifica indirizzo d'invio</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>L'indirizzo inserito "%1" non è un indirizzo bitcoin valido.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book.</source>
+ <translation>L'indirizzo inserito "%1" è già in rubrica.</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Impossibile sbloccare il portamonete.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Generazione della nuova chiave non riuscita.</translation>
+ </message>
+</context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -722,14 +882,42 @@
<translation>Modulo</translation>
</message>
<message>
+ <source>Number of blocks left</source>
+ <translation>Numero di blocchi mancanti</translation>
+ </message>
+ <message>
+ <source>Unknown...</source>
+ <translation>Sconosciuto...</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation>Ora del blocco più recente</translation>
</message>
<message>
+ <source>Progress</source>
+ <translation>Progresso</translation>
+ </message>
+ <message>
+ <source>Progress increase per hour</source>
+ <translation>Aumento dei progressi per ogni ora</translation>
+ </message>
+ <message>
+ <source>calculating...</source>
+ <translation>calcolando...</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation>Tempo stimato al completamento della sincronizzazione.</translation>
+ </message>
+ <message>
<source>Hide</source>
<translation>Nascondi</translation>
</message>
- </context>
+ <message>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation>Sconosciuto. Sincronizzazione Headers (%1)...</translation>
+ </message>
+</context>
<context>
<name>OpenURIDialog</name>
<message>
@@ -748,7 +936,11 @@
<source>Select payment request file</source>
<translation>Seleziona il file di richiesta di pagamento</translation>
</message>
- </context>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>Seleziona il file di richiesta di pagamento da aprire</translation>
+ </message>
+</context>
<context>
<name>OptionsDialog</name>
<message>
@@ -1062,7 +1254,95 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
</context>
<context>
<name>PaymentServer</name>
- </context>
+ <message>
+ <source>Payment request error</source>
+ <translation>Errore di richiesta di pagamento</translation>
+ </message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation>Impossibile avviare bitcoin: gestore click-to-pay</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation>Gestione URI</translation>
+ </message>
+ <message>
+ <source>Payment request fetch URL is invalid: %1</source>
+ <translation>URL di recupero della Richiesta di pagamento non valido: %1</translation>
+ </message>
+ <message>
+ <source>Invalid payment address %1</source>
+ <translation>Indirizzo di pagamento non valido %1</translation>
+ </message>
+ <message>
+ <source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
+ <translation>Impossibile interpretare l'URI! I parametri dell'URI o l'indirizzo Bitcoin potrebbero non essere corretti.</translation>
+ </message>
+ <message>
+ <source>Payment request file handling</source>
+ <translation>Gestione del file di richiesta del pagamento</translation>
+ </message>
+ <message>
+ <source>Payment request file cannot be read! This can be caused by an invalid payment request file.</source>
+ <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 rejected</source>
+ <translation>Richiesta di pagamento respinta</translation>
+ </message>
+ <message>
+ <source>Payment request network doesn't match client network.</source>
+ <translation>La rete della richiesta di pagamento non corrisponde alla rete del client.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Richiesta di pagamento scaduta.</translation>
+ </message>
+ <message>
+ <source>Payment request is not initialized.</source>
+ <translation>La richiesta di pagamento non è stata inizializzata.</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 invalida</translation>
+ </message>
+ <message>
+ <source>Requested payment amount of %1 is too small (considered dust).</source>
+ <translation>L'importo di pagamento di %1 richiesto è troppo basso (considerato come trascurabile).</translation>
+ </message>
+ <message>
+ <source>Refund from %1</source>
+ <translation>Rimborso da %1</translation>
+ </message>
+ <message>
+ <source>Payment request %1 is too large (%2 bytes, allowed %3 bytes).</source>
+ <translation>La richiesta di pagamento %1 è troppo grande (%2 bytes, consentiti %3 bytes)</translation>
+ </message>
+ <message>
+ <source>Error communicating with %1: %2</source>
+ <translation>Errore di comunicazione con %1: %2</translation>
+ </message>
+ <message>
+ <source>Payment request cannot be parsed!</source>
+ <translation>La richiesta di pagamento non può essere processata!</translation>
+ </message>
+ <message>
+ <source>Bad response from server %1</source>
+ <translation> Risposta errata da parte del server %1 </translation>
+ </message>
+ <message>
+ <source>Network request error</source>
+ <translation> Errore di richiesta di rete</translation>
+ </message>
+ <message>
+ <source>Payment acknowledged</source>
+ <translation>Pagamento riconosciuto</translation>
+ </message>
+</context>
<context>
<name>PeerTableModel</name>
<message>
@@ -1073,7 +1353,11 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<source>Node/Service</source>
<translation>Nodo/Servizio</translation>
</message>
- </context>
+ <message>
+ <source>Ping</source>
+ <translation>Ping</translation>
+ </message>
+</context>
<context>
<name>QObject</name>
<message>
@@ -1112,17 +1396,65 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation><numerusform>%n secondo</numerusform><numerusform>%n secondi</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation><numerusform>%n minuto</numerusform><numerusform>%n minuti</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation><numerusform>%n ora</numerusform><numerusform>%n ore</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation><numerusform>%n giorno</numerusform><numerusform>%n giorni</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation><numerusform>%n settimana</numerusform><numerusform>%n settimane</numerusform></translation>
+ </message>
<message>
<source>%1 and %2</source>
<translation>%1 e %2</translation>
</message>
- </context>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation><numerusform>%n anno</numerusform><numerusform>%n anni</numerusform></translation>
+ </message>
+ <message>
+ <source>%1 didn't yet exit safely...</source>
+ <translation>%1 non è ancora stato chiuso in modo sicuro</translation>
+ </message>
+</context>
<context>
<name>QObject::QObject</name>
- </context>
+ <message>
+ <source>Error: %1</source>
+ <translation>Errore: %1</translation>
+ </message>
+</context>
<context>
<name>QRImageWidget</name>
- </context>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;Salva immagine</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>&amp;Copia immagine</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>Salva codice QR</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>Immagine PNG (*.png)</translation>
+ </message>
+</context>
<context>
<name>RPCConsole</name>
<message>
@@ -1282,6 +1614,10 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Attesa ping</translation>
</message>
<message>
+ <source>Min Ping</source>
+ <translation>Ping Minimo</translation>
+ </message>
+ <message>
<source>Time Offset</source>
<translation>Scarto Temporale</translation>
</message>
@@ -1342,6 +1678,18 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>1 &amp;anno</translation>
</message>
<message>
+ <source>&amp;Disconnect</source>
+ <translation>&amp;Disconnetti</translation>
+ </message>
+ <message>
+ <source>Ban for</source>
+ <translation>Bannato per</translation>
+ </message>
+ <message>
+ <source>&amp;Unban</source>
+ <translation>&amp;Sbanna</translation>
+ </message>
+ <message>
<source>Welcome to the %1 RPC console.</source>
<translation>Benvenuto nella console RPC di %1.</translation>
</message>
@@ -1354,6 +1702,10 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Scrivi &lt;b&gt;help&lt;/b&gt; per un riassunto dei comandi disponibili.</translation>
</message>
<message>
+ <source>Network activity disabled</source>
+ <translation>Attività di rete disabilitata</translation>
+ </message>
+ <message>
<source>%1 B</source>
<translation>%1 B</translation>
</message>
@@ -1472,7 +1824,23 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<source>Remove</source>
<translation>Rimuovi</translation>
</message>
- </context>
+ <message>
+ <source>Copy URI</source>
+ <translation>Copia URI</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copia etichetta</translation>
+ </message>
+ <message>
+ <source>Copy message</source>
+ <translation>Copia il messaggio</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copia l'importo</translation>
+ </message>
+</context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -1492,25 +1860,73 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>&amp;Salva Immagine...</translation>
</message>
<message>
+ <source>Request payment to %1</source>
+ <translation>Richiesta di pagamento a %1</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>Informazioni di pagamento</translation>
+ </message>
+ <message>
+ <source>URI</source>
+ <translation>URI</translation>
+ </message>
+ <message>
<source>Address</source>
<translation>Indirizzo</translation>
</message>
<message>
+ <source>Amount</source>
+ <translation>Importo</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>Etichetta</translation>
</message>
- </context>
+ <message>
+ <source>Message</source>
+ <translation>Messaggio</translation>
+ </message>
+ <message>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation> L'URI risultante è troppo lungo, prova a ridurre il testo nell'etichetta / messaggio.</translation>
+ </message>
+ <message>
+ <source>Error encoding URI into QR Code.</source>
+ <translation> Errore nella codifica dell'URI nel codice QR.</translation>
+ </message>
+</context>
<context>
<name>RecentRequestsTableModel</name>
<message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>Etichetta</translation>
</message>
<message>
+ <source>Message</source>
+ <translation>Messaggio</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(nessuna etichetta)</translation>
</message>
- </context>
+ <message>
+ <source>(no message)</source>
+ <translation>(nessun messaggio)</translation>
+ </message>
+ <message>
+ <source>(no amount requested)</source>
+ <translation>(nessun importo richiesto)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation>Richiesto</translation>
+ </message>
+</context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1654,6 +2070,110 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>&amp;Invia</translation>
</message>
<message>
+ <source>Copy quantity</source>
+ <translation>Copia quantità</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copia l'importo</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Copia commissione</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Copia dopo commissione</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Copia byte</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Copia trascurabile</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Copia resto</translation>
+ </message>
+ <message>
+ <source>%1 to %2</source>
+ <translation>%1 a %2</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to send?</source>
+ <translation> Sei sicuro di voler inviare?</translation>
+ </message>
+ <message>
+ <source>added as transaction fee</source>
+ <translation> Includi il costo della transazione</translation>
+ </message>
+ <message>
+ <source>Total Amount %1</source>
+ <translation>Importo Totale %1</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>o</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation>Conferma invio coins</translation>
+ </message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation> L'indirizzo del destinatario non è valido. Si prega di ricontrollare.</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation> L'importo da pagare deve essere maggiore di 0.</translation>
+ </message>
+ <message>
+ <source>The amount exceeds your balance.</source>
+ <translation>Non hai abbastanza fondi</translation>
+ </message>
+ <message>
+ <source>The total exceeds your balance when the %1 transaction fee is included.</source>
+ <translation> Il totale è superiore al tuo saldo attuale includendo la commissione di %1. </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>Transaction creation failed!</source>
+ <translation>Creazione della transazione fallita!</translation>
+ </message>
+ <message>
+ <source>The transaction was rejected with the following reason: %1</source>
+ <translation>La transazione è stata respinta per il seguente motivo: %1</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 numerus="yes">
+ <source>%n block(s)</source>
+ <translation><numerusform>%n blocco</numerusform><numerusform>%n blocchi</numerusform></translation>
+ </message>
+ <message>
+ <source>Pay only the required fee of %1</source>
+ <translation> Paga solamente la commissione richiesta di %1</translation>
+ </message>
+ <message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>Attenzione: Indirizzo Bitcoin non valido</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <translation>Attenzione: Indirizzo per il resto sconosciuto</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(nessuna etichetta)</translation>
</message>
@@ -1739,7 +2259,11 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
</context>
<context>
<name>SendConfirmationDialog</name>
- </context>
+ <message>
+ <source>Yes</source>
+ <translation>Si</translation>
+ </message>
+</context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1837,7 +2361,59 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<source>Reset all verify message fields</source>
<translation>Reimposta tutti i campi della verifica messaggio</translation>
</message>
- </context>
+ <message>
+ <source>Click "Sign Message" to generate signature</source>
+ <translation>Clicca "Firma Messaggio" per generare una firma</translation>
+ </message>
+ <message>
+ <source>The entered address is invalid.</source>
+ <translation>L'indirizzo inserito non è valido.</translation>
+ </message>
+ <message>
+ <source>Please check the address and try again.</source>
+ <translation>Per favore controlla l'indirizzo e prova di nuovo.</translation>
+ </message>
+ <message>
+ <source>The entered address does not refer to a key.</source>
+ <translation>L'indirizzo bitcoin inserito non è associato a nessuna chiave.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock was cancelled.</source>
+ <translation>Sblocco del portamonete annullato.</translation>
+ </message>
+ <message>
+ <source>Private key for the entered address is not available.</source>
+ <translation>La chiave privata per l'indirizzo inserito non è disponibile.</translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation>Firma messaggio fallita.</translation>
+ </message>
+ <message>
+ <source>Message signed.</source>
+ <translation>Messaggio firmato.</translation>
+ </message>
+ <message>
+ <source>The signature could not be decoded.</source>
+ <translation>Non è stato possibile decodificare la firma.</translation>
+ </message>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation>Per favore controlla la firma e prova di nuovo.</translation>
+ </message>
+ <message>
+ <source>The signature did not match the message digest.</source>
+ <translation>La firma non corrisponde al digest del messaggio.</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation>Verifica messaggio fallita.</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation>Messaggio verificato.</translation>
+ </message>
+</context>
<context>
<name>SplashScreen</name>
<message>
@@ -1854,7 +2430,139 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
</context>
<context>
<name>TransactionDesc</name>
- </context>
+ <message>
+ <source>%1/offline</source>
+ <translation>%1/offline</translation>
+ </message>
+ <message>
+ <source>0/unconfirmed, %1</source>
+ <translation>0/non confermati, %1</translation>
+ </message>
+ <message>
+ <source>abandoned</source>
+ <translation>abbandonato</translation>
+ </message>
+ <message>
+ <source>%1/unconfirmed</source>
+ <translation>%1/non confermato</translation>
+ </message>
+ <message>
+ <source>%1 confirmations</source>
+ <translation>%1 conferme</translation>
+ </message>
+ <message>
+ <source>Status</source>
+ <translation>Stato</translation>
+ </message>
+ <message>
+ <source>, has not been successfully broadcast yet</source>
+ <translation>, non è ancora stata trasmessa con successo</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Source</source>
+ <translation>Sorgente</translation>
+ </message>
+ <message>
+ <source>Generated</source>
+ <translation>Generato</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>Da</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>sconosciuto</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation>A</translation>
+ </message>
+ <message>
+ <source>own address</source>
+ <translation>proprio indirizzo</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>sola lettura</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>etichetta</translation>
+ </message>
+ <message>
+ <source>Credit</source>
+ <translation>Credito</translation>
+ </message>
+ <message>
+ <source>not accepted</source>
+ <translation>non accettate</translation>
+ </message>
+ <message>
+ <source>Debit</source>
+ <translation>Debito</translation>
+ </message>
+ <message>
+ <source>Total debit</source>
+ <translation>Debito totale</translation>
+ </message>
+ <message>
+ <source>Total credit</source>
+ <translation>Credito totale</translation>
+ </message>
+ <message>
+ <source>Transaction fee</source>
+ <translation>Commissione transazione</translation>
+ </message>
+ <message>
+ <source>Net amount</source>
+ <translation>Importo netto</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Messaggio</translation>
+ </message>
+ <message>
+ <source>Comment</source>
+ <translation>Commento</translation>
+ </message>
+ <message>
+ <source>Transaction ID</source>
+ <translation>ID della transazione</translation>
+ </message>
+ <message>
+ <source>Merchant</source>
+ <translation>Commerciante</translation>
+ </message>
+ <message>
+ <source>Debug information</source>
+ <translation>Informazione di debug</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation>Transazione</translation>
+ </message>
+ <message>
+ <source>Inputs</source>
+ <translation>Input</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Importo</translation>
+ </message>
+ <message>
+ <source>true</source>
+ <translation>vero</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation>falso</translation>
+ </message>
+</context>
<context>
<name>TransactionDescDialog</name>
<message>
@@ -1865,21 +2573,201 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<context>
<name>TransactionTableModel</name>
<message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Tipo</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>Etichetta</translation>
</message>
<message>
+ <source>Offline</source>
+ <translation>Offline</translation>
+ </message>
+ <message>
+ <source>Unconfirmed</source>
+ <translation>Non confermata</translation>
+ </message>
+ <message>
+ <source>Confirmed (%1 confirmations)</source>
+ <translation>Confermata (%1 conferme)</translation>
+ </message>
+ <message>
+ <source>This block was not received by any other nodes and will probably not be accepted!</source>
+ <translation>Questo blocco non è stato ricevuto da alcun altro nodo e probabilmente non sarà accettato!</translation>
+ </message>
+ <message>
+ <source>Generated but not accepted</source>
+ <translation>Generati, ma non accettati</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Ricevuto tramite</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Inviato a</translation>
+ </message>
+ <message>
+ <source>Payment to yourself</source>
+ <translation>Pagamento a te stesso</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Ottenuto dal mining</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>sola lettura</translation>
+ </message>
+ <message>
+ <source>(n/a)</source>
+ <translation>(n/d)</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(nessuna etichetta)</translation>
</message>
- </context>
+ <message>
+ <source>Transaction status. Hover over this field to show number of confirmations.</source>
+ <translation>Stato della transazione. Passare con il mouse su questo campo per visualizzare il numero di conferme.</translation>
+ </message>
+ <message>
+ <source>Date and time that the transaction was received.</source>
+ <translation>Data e ora in cui la transazione è stata ricevuta.</translation>
+ </message>
+ <message>
+ <source>Type of transaction.</source>
+ <translation>Tipo di transazione.</translation>
+ </message>
+ <message>
+ <source>Whether or not a watch-only address is involved in this transaction.</source>
+ <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>
+</context>
<context>
<name>TransactionView</name>
<message>
+ <source>All</source>
+ <translation>Tutti</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>Oggi</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>Questa settimana</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>Questo mese</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>Il mese scorso</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>Quest'anno</translation>
+ </message>
+ <message>
+ <source>Range...</source>
+ <translation>Intervallo...</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Ricevuto tramite</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Inviato a</translation>
+ </message>
+ <message>
+ <source>To yourself</source>
+ <translation>A te stesso</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Ottenuto dal mining</translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation>Altro</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation>Inserisci un indirizzo o un'etichetta da cercare</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation>Importo minimo</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Copia indirizzo</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Copia etichetta</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Copia l'importo</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Copia l'ID transazione</translation>
+ </message>
+ <message>
+ <source>Copy raw transaction</source>
+ <translation>Copia la transazione raw</translation>
+ </message>
+ <message>
+ <source>Edit label</source>
+ <translation>Modifica l'etichetta</translation>
+ </message>
+ <message>
+ <source>Show transaction details</source>
+ <translation>Mostra i dettagli della transazione</translation>
+ </message>
+ <message>
+ <source>Export Transaction History</source>
+ <translation>Esporta lo storico delle transazioni</translation>
+ </message>
+ <message>
<source>Comma separated file (*.csv)</source>
<translation>Testo CSV (*.csv)</translation>
</message>
<message>
+ <source>Confirmed</source>
+ <translation>Confermato</translation>
+ </message>
+ <message>
+ <source>Watch-only</source>
+ <translation>Sola lettura</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Tipo</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>Etichetta</translation>
</message>
@@ -1888,10 +2776,34 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Indirizzo</translation>
</message>
<message>
+ <source>ID</source>
+ <translation>ID</translation>
+ </message>
+ <message>
<source>Exporting Failed</source>
<translation>Esportazione Fallita</translation>
</message>
- </context>
+ <message>
+ <source>There was an error trying to save the transaction history to %1.</source>
+ <translation>Si è verificato un errore durante il salvataggio dello storico delle transazioni in %1.</translation>
+ </message>
+ <message>
+ <source>Exporting Successful</source>
+ <translation>Esportazione Riuscita</translation>
+ </message>
+ <message>
+ <source>The transaction history was successfully saved to %1.</source>
+ <translation>Lo storico delle transazioni e' stato salvato con successo in %1.</translation>
+ </message>
+ <message>
+ <source>Range:</source>
+ <translation>Intervallo:</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>a</translation>
+ </message>
+</context>
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
@@ -1901,13 +2813,53 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
</context>
<context>
<name>WalletFrame</name>
- </context>
+ <message>
+ <source>No wallet has been loaded.</source>
+ <translation>Non è stato caricato alcun portamonete.</translation>
+ </message>
+</context>
<context>
<name>WalletModel</name>
- </context>
+ <message>
+ <source>Send Coins</source>
+ <translation>Invia Bitcoin</translation>
+ </message>
+</context>
<context>
<name>WalletView</name>
- </context>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;Esporta</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Esporta su file i dati contenuti nella tabella corrente</translation>
+ </message>
+ <message>
+ <source>Backup Wallet</source>
+ <translation>Backup Portamonete</translation>
+ </message>
+ <message>
+ <source>Wallet Data (*.dat)</source>
+ <translation>Dati Portamonete (*.dat)</translation>
+ </message>
+ <message>
+ <source>Backup Failed</source>
+ <translation>Backup Fallito</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the wallet data to %1.</source>
+ <translation>Si è verificato un errore durante il salvataggio dei dati del portamonete in %1.</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation>Backup eseguito con successo</translation>
+ </message>
+ <message>
+ <source>The wallet data was successfully saved to %1.</source>
+ <translation>Il portamonete è stato correttamente salvato in %1.</translation>
+ </message>
+</context>
<context>
<name>bitcoin-core</name>
<message>
@@ -1943,10 +2895,6 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Prune: l'ultima sincronizzazione del wallet risulta essere oltre la riduzione dei dati. È necessario eseguire un -reindex (scaricare nuovamente la blockchain in caso di nodo pruned)</translation>
</message>
<message>
- <source>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, &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à è incompatibile con l'opzione -txindex e -rescan. Attenzione: ripristinando questa opzione l'intera blockchain dovrà essere riscaricata. (default: 0 = disabilita il pruning, &gt;%u = dimensione desiderata in MiB per i file dei blocchi)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Non è possibile un Rescan in modalità pruned. Sarà necessario utilizzare -reindex che farà scaricare nuovamente tutta la blockchain.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_it_IT.ts b/src/qt/locale/bitcoin_it_IT.ts
index 09d40497fa..ebb30f13e4 100644
--- a/src/qt/locale/bitcoin_it_IT.ts
+++ b/src/qt/locale/bitcoin_it_IT.ts
@@ -41,9 +41,21 @@
<source>&amp;Delete</source>
<translation>Cancella</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Scegli l'indirizzo a cui inviare denaro</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>Scegli</translation>
+ </message>
</context>
<context>
<name>AddressTableModel</name>
+ <message>
+ <source>Address</source>
+ <translation>Indirizzo</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -132,6 +144,10 @@
</context>
<context>
<name>ReceiveRequestDialog</name>
+ <message>
+ <source>Address</source>
+ <translation>Indirizzo</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
@@ -168,6 +184,10 @@
</context>
<context>
<name>TransactionView</name>
+ <message>
+ <source>Address</source>
+ <translation>Indirizzo</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
diff --git a/src/qt/locale/bitcoin_ja.ts b/src/qt/locale/bitcoin_ja.ts
index 3b56a76855..f81818896f 100644
--- a/src/qt/locale/bitcoin_ja.ts
+++ b/src/qt/locale/bitcoin_ja.ts
@@ -330,6 +330,10 @@
<translation>クリックするとネットワーク活動を再び有効化します。</translation>
</message>
<message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>未知。ヘッダを同期しています (%1%)...</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>ディスク上のブロックのインデックスを再作成中...</translation>
</message>
@@ -441,10 +445,6 @@
<source>Processing blocks on disk...</source>
<translation>ディスク上のブロックを処理しています...</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></translation>
@@ -486,6 +486,10 @@
<translation>%1 クライアント</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>ピアに接続しています...</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>追跡中...</translation>
</message>
@@ -2205,6 +2209,14 @@
<translation>警告:未知のおつりアドレスです</translation>
</message>
<message>
+ <source>Confirm custom change address</source>
+ <translation>カスタムおつりアドレスを確認</translation>
+ </message>
+ <message>
+ <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source>
+ <translation>おつりとして指定されたアドレスはこのウォレットに属さないもののようです。このウォレットの一部またはすべての資産がこのアドレスへ送金されます。よろしいですか?</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(ラベル無し)</translation>
</message>
@@ -3022,10 +3034,6 @@
<translation>剪定: 最後のウォレット同期ポイントは、選定されたデータよりも過去のものとなっています。-reindexをする必要があります (剪定されたノードの場合、ブロックチェイン全体をダウンロードします)</translation>
</message>
<message>
- <source>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, &gt;%u = target size in MiB to use for block files)</source>
- <translation>古いブロックを剪定する (削除する) ことで記憶容量の必要量を削減する。このモードを有効にすると-txindexや-rescanと互換性がなくなります。警告: この設定の再有効化には全ブロックチェインの再ダウンロードが必要となります。(規定値: 0 = ブロックの剪定無効、&gt;%u = ブロックファイルに使用するMiB単位の目標サイズ)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>剪定モードでは再スキャンを行うことはできません。-reindexを指定し、ブロックチェイン全体を再ダウンロードする必要があります。</translation>
</message>
@@ -3090,6 +3098,14 @@
<translation>ウォレットの取引を変更する際にコマンドを実行 (cmd の %s は TxID に置換される)</translation>
</message>
<message>
+ <source>Extra transactions to keep in memory for compact block reconstructions (default: %u)</source>
+ <translation>コンパクトブロック再構成のために追加のトランザクションをメモリ内に保管しておく (デフォルト: %u)</translation>
+ </message>
+ <message>
+ <source>If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)</source>
+ <translation>このブロックがブロックチェーン内に含まれていた場合には、このブロックおよびそれ以前のすべてのブロックを有効であるとみなし、スクリプトの検証を省略する (0ならすべてを検証、デフォルト: %s、テストネット: %s)</translation>
+ </message>
+ <message>
<source>Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)</source>
<translation>時間オフセット調整値のピア中央値に対する最大の許容値。ローカル時間の見込み値は、接続するピアにより前方ないし後方へ影響されます。(初期値: %u 秒)</translation>
</message>
@@ -3106,6 +3122,14 @@
<translation>%s が有用だと感じられた方はぜひプロジェクトへの貢献をお願いします。ソフトウェアのより詳細な情報については %s をご覧ください。</translation>
</message>
<message>
+ <source>Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, &gt;%u = automatically prune block files to stay under the specified target size in MiB)</source>
+ <translation>古いブロックの剪定 (削除) を有効にすることでストレージの必要量を削減する。これにより pruneblockchain RPC を呼び出すことで指定されたブロックを削除することができます。またターゲットサイズが MiB 単位で指定された場合には古いブロックの自動剪定が有効となります。このモードは -txindex および -rescan オプションと互換性がありません。警告: この設定を最有効化するにはすべてのブロックチェーンの再ダウンロードが必要となります。(デフォルト: 0 = ブロックの剪定を無効化する, 1 = RPC 経由での手動剪定を許可する, &gt;%u = MiB 単位で指定されたターゲットサイズを常に下回るようにブロックファイルを自動的に剪定する)</translation>
+ </message>
+ <message>
+ <source>Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)</source>
+ <translation>ブロック生成時に取り込まれるトランザクションの最低手数料率 (%s/kB 単位)。(デフォルト: %s)</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>
@@ -3126,6 +3150,10 @@
<translation>リスン ポートの割当に UPnP を使用 (初期値: リスン中および-proxyが指定されていない場合は1)</translation>
</message>
<message>
+ <source>Username and hashed password for JSON-RPC connections. The field &lt;userpw&gt; comes in the format: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=&lt;USERNAME&gt;/rpcpassword=&lt;PASSWORD&gt; pair of arguments. This option can be specified multiple times</source>
+ <translation>JSON-RPC 接続時のユーザ名とハッシュ化されたパスワード。&lt;userpw&gt; フィールドのフォーマットは &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;。標準的な Python スクリプトが share/rpcuser 内に含まれています。クライアントは通常の場合には rpcuser=&lt;USERNAME&gt;/rpcpassword=&lt;PASSWORD&gt; を利用して接続を行います。このオプションは複数回指定できます。</translation>
+ </message>
+ <message>
<source>Wallet will not create transactions that violate mempool chain limits (default: %u)</source>
<translation>ウォレットがmempoolチェーン制限数を超えてトランザクションを作らないようにする (初期値: %u)</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ka.ts b/src/qt/locale/bitcoin_ka.ts
index 920f44758a..c51a611b3c 100644
--- a/src/qt/locale/bitcoin_ka.ts
+++ b/src/qt/locale/bitcoin_ka.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>
@@ -37,9 +41,29 @@
<source>&amp;Delete</source>
<translation>&amp;წაშლა</translation>
</message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>&amp;არჩევა</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>გამმგზავნი მისამართ</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>მიმღები მისამართი</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;რედაქტირება</translation>
+ </message>
</context>
<context>
<name>AddressTableModel</name>
+ <message>
+ <source>Address</source>
+ <translation>მისამართი</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -59,6 +83,22 @@
<source>Repeat new passphrase</source>
<translation>გაიმეორეთ ახალი ფრაზა-პაროლი</translation>
</message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>საფულის დაშიფრვა</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>საფულის განბლოკვა</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>საფულის განბლოკვა</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>პაროლის შეცვლა</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
@@ -102,6 +142,14 @@
<translation>გასვლა</translation>
</message>
<message>
+ <source>&amp;About %1</source>
+ <translation>%1-ის &amp;შესახებ</translation>
+ </message>
+ <message>
+ <source>Show information about %1</source>
+ <translation>%1-ის შესახებ ინფორმაციის ჩვენება</translation>
+ </message>
+ <message>
<source>About &amp;Qt</source>
<translation>&amp;Qt-ს შესახებ</translation>
</message>
@@ -238,10 +286,6 @@
<translation>საკომანდო სტრიქონის ოპ&amp;ციები</translation>
</message>
<message>
- <source>No block source available...</source>
- <translation>ბლოკების წყარო მიუწვდომელია...</translation>
- </message>
- <message>
<source>%1 behind</source>
<translation>%1 გავლილია</translation>
</message>
@@ -270,8 +314,36 @@
<translation>განახლებულია</translation>
</message>
<message>
+ <source>%1 client</source>
+ <translation>%1 კლიენტი</translation>
+ </message>
+ <message>
<source>Catching up...</source>
- <translation>ჩართვა...</translation>
+ <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>Address: %1
+</source>
+ <translation>მისამართი: %1
+</translation>
</message>
<message>
<source>Sent transaction</source>
@@ -309,6 +381,10 @@
<translation>საკომისიო:</translation>
</message>
<message>
+ <source>Dust:</source>
+ <translation>მტვერი:</translation>
+ </message>
+ <message>
<source>After Fee:</source>
<translation>დამატებითი საკომისიო:</translation>
</message>
@@ -344,7 +420,19 @@
<source>Confirmed</source>
<translation>დადასტურებულია</translation>
</message>
- </context>
+ <message>
+ <source>yes</source>
+ <translation>დიახ</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>არა</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(ხურდა)</translation>
+ </message>
+</context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -398,6 +486,14 @@
<translation>ვერსია</translation>
</message>
<message>
+ <source>(%1-bit)</source>
+ <translation>(%1-ბიტი)</translation>
+ </message>
+ <message>
+ <source>About %1</source>
+ <translation>%1-ის შესახებ</translation>
+ </message>
+ <message>
<source>Command-line options</source>
<translation>კომანდების ზოლის ოპციები</translation>
</message>
@@ -409,6 +505,10 @@
<source>command-line options</source>
<translation>კომანდების ზოლის ოპციები</translation>
</message>
+ <message>
+ <source>UI Options:</source>
+ <translation>მომხმარებლის ინტერფეისის ოპციები:</translation>
+ </message>
</context>
<context>
<name>Intro</name>
@@ -417,6 +517,10 @@
<translation>მოგესალმებით</translation>
</message>
<message>
+ <source>Welcome to %1.</source>
+ <translation>კეთილი იყოს თქვენი მობრძანება %1-ში.</translation>
+ </message>
+ <message>
<source>Use the default data directory</source>
<translation>ნაგულისხმევი კატალოგის გამოყენება</translation>
</message>
@@ -428,7 +532,15 @@
<source>Error</source>
<translation>შეცდომა</translation>
</message>
- </context>
+ <message numerus="yes">
+ <source>%n GB of free space available</source>
+ <translation><numerusform>ხელმისაწვდომია თავისუფალი სივრცის %n გბ</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation><numerusform>(საჭირო %n გბ-დან)</numerusform></translation>
+ </message>
+</context>
<context>
<name>ModalOverlay</name>
<message>
@@ -436,9 +548,25 @@
<translation>ფორმა</translation>
</message>
<message>
+ <source>Unknown...</source>
+ <translation>უცნობი...</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation>ბოლო ბლოკის დრო</translation>
</message>
+ <message>
+ <source>Progress</source>
+ <translation>პროგრესი</translation>
+ </message>
+ <message>
+ <source>calculating...</source>
+ <translation>მიმდინარეობს გამოთვლა...</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>დამალვა</translation>
+ </message>
</context>
<context>
<name>OpenURIDialog</name>
@@ -506,6 +634,10 @@
<translation>ს&amp;აფულე</translation>
</message>
<message>
+ <source>Expert</source>
+ <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>
@@ -530,6 +662,18 @@
<translation>პროქსის პორტი (მაგ.: 9050)</translation>
</message>
<message>
+ <source>IPv4</source>
+ <translation>IPv4</translation>
+ </message>
+ <message>
+ <source>IPv6</source>
+ <translation>IPv6</translation>
+ </message>
+ <message>
+ <source>Tor</source>
+ <translation>Tor</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation>&amp;ფანჯარა</translation>
</message>
@@ -876,6 +1020,10 @@
<source>&amp;Save Image...</source>
<translation>გამო&amp;სახულების შენახვა...</translation>
</message>
+ <message>
+ <source>Address</source>
+ <translation>მისამართი</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
@@ -939,6 +1087,10 @@
<translation>ტრანსაქციის საფასური - საკომისიო:</translation>
</message>
<message>
+ <source>Hide</source>
+ <translation>დამალვა</translation>
+ </message>
+ <message>
<source>Send to multiple recipients at once</source>
<translation>გაგზავნა რამდენიმე რეციპიენტთან ერთდროულად</translation>
</message>
@@ -951,6 +1103,10 @@
<translation>ფორმის ყველა ველის წაშლა</translation>
</message>
<message>
+ <source>Dust:</source>
+ <translation>მტვერი:</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>გ&amp;ასუფთავება</translation>
</message>
@@ -1136,6 +1292,10 @@
</context>
<context>
<name>TransactionView</name>
+ <message>
+ <source>Address</source>
+ <translation>მისამართი</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
diff --git a/src/qt/locale/bitcoin_ko_KR.ts b/src/qt/locale/bitcoin_ko_KR.ts
index a80c6ccc45..c104bdd0db 100644
--- a/src/qt/locale/bitcoin_ko_KR.ts
+++ b/src/qt/locale/bitcoin_ko_KR.ts
@@ -318,6 +318,22 @@
<translation>&amp;URI 열기...</translation>
</message>
<message>
+ <source>Click to disable network activity.</source>
+ <translation>네트워크 활동을 중지하려면 클릭.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>네트워크 활동이 정지됨.</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>네트워크 활동을 다시 시작하려면 클릭.</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>헤더 동기화중 (%1%)...</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>디스크에서 블록 다시 색인중...</translation>
</message>
@@ -429,13 +445,9 @@
<source>Processing blocks on disk...</source>
<translation>디스크에서 블록 처리중...</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></translation>
+ <translation><numerusform>%n 블록 만큼의 거래 기록이 처리됨.</numerusform></translation>
</message>
<message>
<source>%1 behind</source>
@@ -474,6 +486,10 @@
<translation>%1 클라이언트</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>피어에 연결중...</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>블록 따라잡기...</translation>
</message>
@@ -516,14 +532,26 @@
<translation>들어오고 있는 거래</translation>
</message>
<message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation>HD 키 생성이 &lt;b&gt;활성화되었습니다&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation>HD 키 생성이 &lt;b&gt;비활성화되었습니다&lt;/b&gt;</translation>
+ </message>
+ <message>
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
- <translation>지갑이 암호화 되었고 현재 차단해제 되었습니다</translation>
+ <translation>지갑이 &lt;b&gt;암호화&lt;/b&gt; 되었고 현재 &lt;b&gt;잠금해제&lt;/b&gt; 되었습니다</translation>
</message>
<message>
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
- <translation>지갑이 암호화 되었고 현재 잠겨져 있습니다</translation>
+ <translation>지갑이 &lt;b&gt;암호화&lt;/b&gt; 되었고 현재 &lt;b&gt;잠겨져&lt;/b&gt; 있습니다</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>치명적인 오류가 발생했습니다. 비트코인을 더이상 안전하게 진행할 수 없어 곧 종료합니다.</translation>
</message>
- </context>
+</context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -556,7 +584,7 @@
</message>
<message>
<source>Change:</source>
- <translation>체인지:</translation>
+ <translation>잔돈:</translation>
</message>
<message>
<source>(un)select all</source>
@@ -655,6 +683,10 @@
<translation>아니요</translation>
</message>
<message>
+ <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
+ <translation>수령인이 현재 더스트 임계값보다 작은 양을 수신하면 이 라벨이 빨간색으로 변합니다.</translation>
+ </message>
+ <message>
<source>Can vary +/- %1 satoshi(s) per input.</source>
<translation>입력마다 +/- %1 사토시(s)가 변할 수 있습니다.</translation>
</message>
@@ -820,7 +852,7 @@
</message>
<message>
<source>%1 will download and store a copy of the Bitcoin block chain. At least %2GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory.</source>
- <translation>%1가 블럭체인의 복사본을 다운로드 저장합니다. 적어도 %2GB의 데이터가 이 폴더에 저장되며 시간이 경과할수록 점차 증가합니다. 그리고 지갑 또한 이 폴더에 저장됩니다. </translation>
+ <translation>%1가 블록체인의 복사본을 다운로드 저장합니다. 적어도 %2GB의 데이터가 이 폴더에 저장되며 시간이 경과할수록 점차 증가합니다. 그리고 지갑 또한 이 폴더에 저장됩니다. </translation>
</message>
<message>
<source>Use the default data directory</source>
@@ -854,14 +886,50 @@
<translation>유형</translation>
</message>
<message>
+ <source>Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source>
+ <translation>최근 거래는 아직 보이지 않을 것입니다, 그러므로 당신의 지갑의 잔액이 틀릴 수도 있습니다. 이 정보는 비트코인 네트워크와 완전한 동기화가 완료되면 아래의 설명과 같이 정확해집니다.</translation>
+ </message>
+ <message>
+ <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source>
+ <translation>아직 표시되지 않은 거래의 영향을 받는 비트코인을 사용하려고 하는 것은 네트워크에서 허가되지 않습니다.</translation>
+ </message>
+ <message>
+ <source>Number of blocks left</source>
+ <translation>남은 블록의 수</translation>
+ </message>
+ <message>
+ <source>Unknown...</source>
+ <translation>알수없음...</translation>
+ </message>
+ <message>
<source>Last block time</source>
- <translation>최종 블럭 시각</translation>
+ <translation>최종 블록 시각</translation>
+ </message>
+ <message>
+ <source>Progress</source>
+ <translation>진행</translation>
+ </message>
+ <message>
+ <source>Progress increase per hour</source>
+ <translation>시간당 진행 증가율</translation>
+ </message>
+ <message>
+ <source>calculating...</source>
+ <translation>계산중...</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation>동기화 완료까지 예상 시간</translation>
</message>
<message>
<source>Hide</source>
<translation>숨기기</translation>
</message>
- </context>
+ <message>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation>알수없음. 헤더 동기화중 (%1)...</translation>
+ </message>
+</context>
<context>
<name>OpenURIDialog</name>
<message>
@@ -933,7 +1001,7 @@
</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 (예. 블록 탐색기)는 거래 탭의 컨텍스트 메뉴에 나타납니다. URL의 %s는 트랜잭션 해시값으로 대체됩니다. 여러 URLs는 수직 바 | 에서 나누어 집니다.</translation>
+ <translation>서드-파티 URLs (예. 블록 탐색기)는 거래 탭의 컨텍스트 메뉴에 나타납니다. URL의 %s는 거래 해시값으로 대체됩니다. 여러 URLs는 수직 바 | 에서 나누어 집니다.</translation>
</message>
<message>
<source>Third party transaction URLs</source>
@@ -973,7 +1041,7 @@
</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>검증되지 않은 잔돈 쓰기를 비활성화하면 트랜잭션이 적어도 1회 이상 검증되기 전까지 그 트랜잭션의 거스름돈은 사용할 수 없습니다. 이는 잔액 계산 방법에도 영향을 미칩니다.</translation>
+ <translation>검증되지 않은 잔돈 쓰기를 비활성화하면 거래가 적어도 1회 이상 검증되기 전까지 그 거래의 거스름돈은 사용할 수 없습니다. 이는 잔액 계산 방법에도 영향을 미칩니다.</translation>
</message>
<message>
<source>&amp;Spend unconfirmed change</source>
@@ -1132,7 +1200,7 @@
</message>
<message>
<source>Watch-only:</source>
- <translation>모니터링 지갑:</translation>
+ <translation>조회전용:</translation>
</message>
<message>
<source>Available:</source>
@@ -1172,7 +1240,7 @@
</message>
<message>
<source>Your current balance in watch-only addresses</source>
- <translation>모니터링 지갑의 현재 잔액</translation>
+ <translation>조회전용 주소의 현재 잔액</translation>
</message>
<message>
<source>Spendable:</source>
@@ -1184,15 +1252,15 @@
</message>
<message>
<source>Unconfirmed transactions to watch-only addresses</source>
- <translation>모니터링 지갑의 검증되지 않은 트랜잭션</translation>
+ <translation>조회전용 주소의 검증되지 않은 거래</translation>
</message>
<message>
<source>Mined balance in watch-only addresses that has not yet matured</source>
- <translation>모니터링 지갑의 채굴된 잔액 중 숙성되지 않은 것</translation>
+ <translation>조회전용 주소의 채굴된 잔액 중 숙성되지 않은 것</translation>
</message>
<message>
<source>Current total balance in watch-only addresses</source>
- <translation>모니터링 지갑의 현재 잔액</translation>
+ <translation>조회전용 주소의 현재 잔액</translation>
</message>
</context>
<context>
@@ -1203,13 +1271,89 @@
</message>
<message>
<source>Cannot start bitcoin: click-to-pay handler</source>
- <translation>비트코인을 시작할 수 없습니다: 지급제어기를 클릭하시오</translation>
+ <translation>비트코인을 시작할 수 없습니다: 지급제어기를 클릭하세요</translation>
</message>
<message>
<source>URI handling</source>
<translation>URI 핸들링</translation>
</message>
- </context>
+ <message>
+ <source>Payment request fetch URL is invalid: %1</source>
+ <translation>지불 요청의 URL이 올바르지 않습니다: %1</translation>
+ </message>
+ <message>
+ <source>Invalid payment address %1</source>
+ <translation>잘못된 지불 주소입니다 %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의 파싱에 문제가 발생했습니다. 잘못된 비트코인 주소나 URI 파라미터 구성에 오류가 존재할 수 있습니다.</translation>
+ </message>
+ <message>
+ <source>Payment request file handling</source>
+ <translation>지불이 파일 처리를 요청합니다</translation>
+ </message>
+ <message>
+ <source>Payment request file cannot be read! This can be caused by an invalid payment request file.</source>
+ <translation>지불 요청 파일을 읽을 수 없습니다. 이것은 잘못된 지불 요청 파일에 의해 발생하는 오류일 수 있습니다.</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>Payment request expired.</source>
+ <translation>지불 요청이 만료됨.</translation>
+ </message>
+ <message>
+ <source>Payment request is not initialized.</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>Requested payment amount of %1 is too small (considered dust).</source>
+ <translation>요청한 금액 %1의 양이 너무 적습니다. (스팸성 거래로 간주)</translation>
+ </message>
+ <message>
+ <source>Refund from %1</source>
+ <translation>%1 으로부터의 환불</translation>
+ </message>
+ <message>
+ <source>Payment request %1 is too large (%2 bytes, allowed %3 bytes).</source>
+ <translation>지불 요청 %1은 너무 큽니다 (%2 바이트, %3 바이트까지 허용됩니다).</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>Network request error</source>
+ <translation>네트워크 요청 에러</translation>
+ </message>
+ <message>
+ <source>Payment acknowledged</source>
+ <translation>지불이 승인됨</translation>
+ </message>
+</context>
<context>
<name>PeerTableModel</name>
<message>
@@ -1220,7 +1364,15 @@
<source>Node/Service</source>
<translation>노드/서비스</translation>
</message>
- </context>
+ <message>
+ <source>NodeId</source>
+ <translation>노드 ID</translation>
+ </message>
+ <message>
+ <source>Ping</source>
+ <translation>핑</translation>
+ </message>
+</context>
<context>
<name>QObject</name>
<message>
@@ -1259,17 +1411,73 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation><numerusform>%n 초</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation><numerusform>%n 분</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation><numerusform>%n 시간</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation><numerusform>&amp;n 일</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation><numerusform>%n 주</numerusform></translation>
+ </message>
<message>
<source>%1 and %2</source>
<translation>%1 그리고 %2</translation>
</message>
- </context>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation><numerusform>%n 년</numerusform></translation>
+ </message>
+ <message>
+ <source>%1 didn't yet exit safely...</source>
+ <translation>%1가 아직 안전하게 종료되지 않았습니다...</translation>
+ </message>
+</context>
<context>
<name>QObject::QObject</name>
- </context>
+ <message>
+ <source>Error: Specified data directory "%1" does not exist.</source>
+ <translation>에러: 지정한 데이터 폴더 "%1"은 존재하지 않습니다.</translation>
+ </message>
+ <message>
+ <source>Error: Cannot parse configuration file: %1. Only use key=value syntax.</source>
+ <translation>에러: 설정파일을 파싱할수 없습니다: %1. key=value syntax만 사용가능합니다.</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation>에러: %1</translation>
+ </message>
+</context>
<context>
<name>QRImageWidget</name>
- </context>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>이미지 저장(&amp;S)...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>이미지 복사(&amp;C)</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>QR코드 저장</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>PNG 이미지(*.png)</translation>
+ </message>
+</context>
<context>
<name>RPCConsole</name>
<message>
@@ -1318,11 +1526,11 @@
</message>
<message>
<source>Block chain</source>
- <translation>블럭 체인</translation>
+ <translation>블록 체인</translation>
</message>
<message>
<source>Current number of blocks</source>
- <translation>현재 블럭 수</translation>
+ <translation>현재 블록 수</translation>
</message>
<message>
<source>Memory Pool</source>
@@ -1330,7 +1538,7 @@
</message>
<message>
<source>Current number of transactions</source>
- <translation>현재 트랜잭션 수</translation>
+ <translation>현재 거래 수</translation>
</message>
<message>
<source>Memory usage</source>
@@ -1429,12 +1637,16 @@
<translation>Ping 대기</translation>
</message>
<message>
+ <source>Min Ping</source>
+ <translation>최소 핑</translation>
+ </message>
+ <message>
<source>Time Offset</source>
<translation>시간 오프셋</translation>
</message>
<message>
<source>Last block time</source>
- <translation>최종 블럭 시각</translation>
+ <translation>최종 블록 시각</translation>
</message>
<message>
<source>&amp;Open</source>
@@ -1489,6 +1701,18 @@
<translation>1년(&amp;Y)</translation>
</message>
<message>
+ <source>&amp;Disconnect</source>
+ <translation>접속 끊기(&amp;D)</translation>
+ </message>
+ <message>
+ <source>Ban for</source>
+ <translation>추방</translation>
+ </message>
+ <message>
+ <source>&amp;Unban</source>
+ <translation>노드 추방 취소(&amp;U)</translation>
+ </message>
+ <message>
<source>Welcome to the %1 RPC console.</source>
<translation>%1 RPC 콘솔에 오신걸 환영합니다</translation>
</message>
@@ -1501,6 +1725,14 @@
<translation>사용할 수 있는 명령을 둘러보려면 &lt;b&gt;help&lt;/b&gt;를 입력하십시오.</translation>
</message>
<message>
+ <source>WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramification of a command.</source>
+ <translation>경고 : 사기꾼이 사용자에게 여기에 명령을 입력하게 하여 지갑 내용을 훔칠수 있다는 사실을 알려드립니다. 명령어를 완전히 이해하지 못한다면 콘솔을 사용하지 마십시오.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled</source>
+ <translation>네트워크 활동이 정지됨.</translation>
+ </message>
+ <message>
<source>%1 B</source>
<translation>%1 바이트</translation>
</message>
@@ -1620,10 +1852,18 @@
<translation>삭제</translation>
</message>
<message>
+ <source>Copy URI</source>
+ <translation>URI 복사</translation>
+ </message>
+ <message>
<source>Copy label</source>
<translation>라벨 복사</translation>
</message>
<message>
+ <source>Copy message</source>
+ <translation>메시지 복사</translation>
+ </message>
+ <message>
<source>Copy amount</source>
<translation>거래액 복사</translation>
</message>
@@ -1647,14 +1887,42 @@
<translation>이미지 저장(&amp;S)...</translation>
</message>
<message>
+ <source>Request payment to %1</source>
+ <translation>%1에 지불을 요청했습니다</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>지불 정보</translation>
+ </message>
+ <message>
+ <source>URI</source>
+ <translation>URI</translation>
+ </message>
+ <message>
<source>Address</source>
<translation>주소</translation>
</message>
<message>
+ <source>Amount</source>
+ <translation>거래액</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>라벨</translation>
</message>
- </context>
+ <message>
+ <source>Message</source>
+ <translation>메시지</translation>
+ </message>
+ <message>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation>URI 결과가 너무 길음, 라벨/메세지의 글을 줄이도록 하세요.</translation>
+ </message>
+ <message>
+ <source>Error encoding URI into QR Code.</source>
+ <translation>URI를 QR 코드로 인코딩하는 중 오류가 발생했습니다.</translation>
+ </message>
+</context>
<context>
<name>RecentRequestsTableModel</name>
<message>
@@ -1666,10 +1934,26 @@
<translation>라벨</translation>
</message>
<message>
+ <source>Message</source>
+ <translation>메시지</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(라벨 없음)</translation>
</message>
- </context>
+ <message>
+ <source>(no message)</source>
+ <translation>(메세지가 없습니다)</translation>
+ </message>
+ <message>
+ <source>(no amount requested)</source>
+ <translation>(요청한 거래액 없음)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation>요청됨</translation>
+ </message>
+</context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1714,7 +1998,7 @@
</message>
<message>
<source>Change:</source>
- <translation>체인지:</translation>
+ <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>
@@ -1742,7 +2026,7 @@
</message>
<message>
<source>If the custom fee is set to 1000 satoshis and the transaction is only 250 bytes, then "per kilobyte" only pays 250 satoshis in fee, while "total at least" pays 1000 satoshis. For transactions bigger than a kilobyte both pay by kilobyte.</source>
- <translation>사용자 정의 수수료가 1000사토시로 지정된 경우 트랜잭션의 크기가 250바이트 일 경우 1킬로바이트당 250사토시만 지불되지만 "최소 수수료"에선 1000사토시가 지불됩니다. 1킬로바이트가 넘는 트랜잭션인 경우 어떠한 경우에든 1킬로바이트 기준으로 지불됩니다.</translation>
+ <translation>사용자 정의 수수료가 1000사토시로 지정된 경우 거래의 크기가 250바이트 일 경우 1킬로바이트당 250사토시만 지불되지만 "최소 수수료"에선 1000사토시가 지불됩니다. 1킬로바이트가 넘는 거래인 경우 어떠한 경우에든 1킬로바이트 기준으로 지불됩니다.</translation>
</message>
<message>
<source>Hide</source>
@@ -1754,11 +2038,11 @@
</message>
<message>
<source>Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks. But be aware that this can end up in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source>
- <translation>블록의 용량보다 트랜잭션의 용량이 작은 경우에는 최소한의 수수료만으로도 충분합니다. 그러나 비트코인 네트워크의 처리량보다 더 많은 트랜잭션 요구는 영원히 검증이 안 될 수도 있습니다.</translation>
+ <translation>블록의 용량보다 거래의 용량이 작은 경우에는 최소한의 수수료만으로도 충분합니다. 그러나 비트코인 네트워크의 처리량보다 더 많은 거래 요구는 영원히 검증이 안 될 수도 있습니다.</translation>
</message>
<message>
<source>(read the tooltip)</source>
- <translation>(툴팁을 읽어보세요)</translation>
+ <translation>(툴팁을 꼭 읽어보세요)</translation>
</message>
<message>
<source>Recommended:</source>
@@ -1770,7 +2054,7 @@
</message>
<message>
<source>(Smart fee not initialized yet. This usually takes a few blocks...)</source>
- <translation>(Smart fee가 아직 초기화되지 않았습니다. 블록 분석이 완료될 때 까지 기다려주십시오...)</translation>
+ <translation>(Smart fee가 아직 초기화 되지 않았습니다. 블록 분석이 완전하게 끝날 때 까지 기다려주십시오...)</translation>
</message>
<message>
<source>normal</source>
@@ -1797,6 +2081,10 @@
<translation>더스트:</translation>
</message>
<message>
+ <source>Confirmation time target:</source>
+ <translation>승인 시간 목표:</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>모두 지우기(&amp;A)</translation>
</message>
@@ -1841,6 +2129,94 @@
<translation>잔돈 복사</translation>
</message>
<message>
+ <source>%1 to %2</source>
+ <translation>%1을(를) %2(으)로</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to send?</source>
+ <translation>정말로 보내시겠습니까?</translation>
+ </message>
+ <message>
+ <source>added as transaction fee</source>
+ <translation>거래 수수료로 추가됨</translation>
+ </message>
+ <message>
+ <source>Total Amount %1</source>
+ <translation>총 액수 %1</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>또는</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation>코인 전송을 확인</translation>
+ </message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>수령인 주소가 정확하지 않습니다. 재확인 바랍니다</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation>지불하는 금액은 0 보다 커야 합니다.</translation>
+ </message>
+ <message>
+ <source>The amount exceeds your balance.</source>
+ <translation>잔고를 초과하였습니다.</translation>
+ </message>
+ <message>
+ <source>The total exceeds your balance when the %1 transaction fee is included.</source>
+ <translation>%1 의 거래수수료를 포함하면 잔고를 초과합니다.</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation>중복된 주소 발견: 한번에 하나의 주소에만 작업할 수 있습니다.</translation>
+ </message>
+ <message>
+ <source>Transaction creation failed!</source>
+ <translation>거래를 생성하는 것을 실패하였습니다!</translation>
+ </message>
+ <message>
+ <source>The transaction was rejected with the following reason: %1</source>
+ <translation>거래가 다음과 같은 이유로 거부되었습니다: %1</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>%n block(s)</source>
+ <translation><numerusform>%n 블록</numerusform></translation>
+ </message>
+ <message>
+ <source>Pay only the required fee of %1</source>
+ <translation>오직 %1 만의 수수료를 지불하기</translation>
+ </message>
+ <message numerus="yes">
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation><numerusform>%n 블록 안에 승인이 시작될 것으로 추정됩니다.</numerusform></translation>
+ </message>
+ <message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>경고: 잘못된 비트코인주소입니다</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <translation>경고: 알려지지 않은 주소변경입니다</translation>
+ </message>
+ <message>
+ <source>Confirm custom change address</source>
+ <translation>맞춤 주소 변경 확인</translation>
+ </message>
+ <message>
+ <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source>
+ <translation>변경하기 위해 선택한 주소는 이 지갑의 일부가 아닙니다. 지갑에 있는 일부 또는 모든 금액을 이 주소로 보낼 수 있습니다. 확실합니까?</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(라벨 없음)</translation>
</message>
@@ -1923,10 +2299,18 @@
<source>Memo:</source>
<translation>메모:</translation>
</message>
- </context>
+ <message>
+ <source>Enter a label for this address to add it to your address book</source>
+ <translation>주소록에 추가하려면 라벨을 입력하세요</translation>
+ </message>
+</context>
<context>
<name>SendConfirmationDialog</name>
- </context>
+ <message>
+ <source>Yes</source>
+ <translation>예</translation>
+ </message>
+</context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1935,7 +2319,7 @@
</message>
<message>
<source>Do not shut down the computer until this window disappears.</source>
- <translation>창이 사라지기 전까지 컴퓨터를 끄지마시오.</translation>
+ <translation>이 창이 사라지기 전까지 컴퓨터를 끄지 마세요.</translation>
</message>
</context>
<context>
@@ -2024,7 +2408,59 @@
<source>Reset all verify message fields</source>
<translation>모든 검증 메시지 필드 재설정</translation>
</message>
- </context>
+ <message>
+ <source>Click "Sign Message" to generate signature</source>
+ <translation>서명을 만들려면 "메시지 서명"을 누르십시오</translation>
+ </message>
+ <message>
+ <source>The entered address is invalid.</source>
+ <translation>입력한 주소가 잘못되었습니다.</translation>
+ </message>
+ <message>
+ <source>Please check the address and try again.</source>
+ <translation>주소를 확인하고 다시 시도하십시오.</translation>
+ </message>
+ <message>
+ <source>The entered address does not refer to a key.</source>
+ <translation>입력한 주소는 키에서 참조하지 않습니다.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock was cancelled.</source>
+ <translation>지갑 잠금 해제를 취소했습니다.</translation>
+ </message>
+ <message>
+ <source>Private key for the entered address is not available.</source>
+ <translation>입력한 주소에 대한 개인키가 없습니다.</translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation>메시지 서명에 실패했습니다.</translation>
+ </message>
+ <message>
+ <source>Message signed.</source>
+ <translation>메시지를 서명했습니다.</translation>
+ </message>
+ <message>
+ <source>The signature could not be decoded.</source>
+ <translation>서명을 해독할 수 없습니다.</translation>
+ </message>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation>서명을 확인하고 다시 시도하십시오.</translation>
+ </message>
+ <message>
+ <source>The signature did not match the message digest.</source>
+ <translation>메시지 다이제스트와 서명이 일치하지 않습니다.</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation>메시지 검증에 실패했습니다.</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation>메시지를 검증했습니다.</translation>
+ </message>
+</context>
<context>
<name>SplashScreen</name>
<message>
@@ -2041,18 +2477,190 @@
</context>
<context>
<name>TransactionDesc</name>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>%n개의 더 많은 블록 열기</numerusform></translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>%1 까지 열림</translation>
+ </message>
+ <message>
+ <source>conflicted with a transaction with %1 confirmations</source>
+ <translation>%1 승인이 있는 거래와 충돌 함</translation>
+ </message>
+ <message>
+ <source>%1/offline</source>
+ <translation>%1/오프라인</translation>
+ </message>
+ <message>
+ <source>0/unconfirmed, %1</source>
+ <translation>0/미승인, %1</translation>
+ </message>
+ <message>
+ <source>in memory pool</source>
+ <translation>메모리 풀 안에 있음</translation>
+ </message>
+ <message>
+ <source>not in memory pool</source>
+ <translation>메모리 풀 안에 없음</translation>
+ </message>
+ <message>
+ <source>abandoned</source>
+ <translation>버려진</translation>
+ </message>
+ <message>
+ <source>%1/unconfirmed</source>
+ <translation>%1/미확인</translation>
+ </message>
+ <message>
+ <source>%1 confirmations</source>
+ <translation>%1 확인됨</translation>
+ </message>
+ <message>
+ <source>Status</source>
+ <translation>상태</translation>
+ </message>
+ <message>
+ <source>, has not been successfully broadcast yet</source>
+ <translation>. 아직 성공적으로 통보하지 않음</translation>
+ </message>
+ <message numerus="yes">
+ <source>, broadcast through %n node(s)</source>
+ <translation><numerusform>, %n개 노드를 통해 전파</numerusform></translation>
+ </message>
<message>
<source>Date</source>
<translation>날짜</translation>
</message>
- </context>
+ <message>
+ <source>Source</source>
+ <translation>소스</translation>
+ </message>
+ <message>
+ <source>Generated</source>
+ <translation>생성됨</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>으로부터</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>알수없음</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation>에게</translation>
+ </message>
+ <message>
+ <source>own address</source>
+ <translation>자신의 주소</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>조회전용</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>라벨</translation>
+ </message>
+ <message>
+ <source>Credit</source>
+ <translation>입금액</translation>
+ </message>
+ <message numerus="yes">
+ <source>matures in %n more block(s)</source>
+ <translation><numerusform>%n개의 더 많은 블록을 숙성</numerusform></translation>
+ </message>
+ <message>
+ <source>not accepted</source>
+ <translation>허용되지 않음</translation>
+ </message>
+ <message>
+ <source>Debit</source>
+ <translation>출금액</translation>
+ </message>
+ <message>
+ <source>Total debit</source>
+ <translation>총 출금액</translation>
+ </message>
+ <message>
+ <source>Total credit</source>
+ <translation>총 입금액</translation>
+ </message>
+ <message>
+ <source>Transaction fee</source>
+ <translation>거래 수수료</translation>
+ </message>
+ <message>
+ <source>Net amount</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>
+ <message>
+ <source>Transaction total size</source>
+ <translation>거래 총 크기</translation>
+ </message>
+ <message>
+ <source>Output index</source>
+ <translation>출력 인덱스</translation>
+ </message>
+ <message>
+ <source>Merchant</source>
+ <translation>상인</translation>
+ </message>
+ <message>
+ <source>Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source>
+ <translation>신규 채굴된 코인이 사용되기 위해서는 %1 개의 블록이 경과되어야 합니다. 블록을 생성할 때 블록체인에 추가되도록 네트워크에 전파되는 과정을 거치는데, 블록체인에 포함되지 못하고 실패한다면 해당 블록의 상태는 '미승인'으로 표현되고 비트코인 또한 사용될 수 없습니다. 이 현상은 다른 노드가 비슷한 시간대에 동시에 블록을 생성할 때 종종 발생할 수 있습니다. </translation>
+ </message>
+ <message>
+ <source>Debug information</source>
+ <translation>디버깅 정보</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation>거래</translation>
+ </message>
+ <message>
+ <source>Inputs</source>
+ <translation>입력</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>거래액</translation>
+ </message>
+ <message>
+ <source>true</source>
+ <translation>참</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation>거짓</translation>
+ </message>
+</context>
<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>이 창은 거래의 세부내역을 보여줍니다</translation>
</message>
- </context>
+ <message>
+ <source>Details for %1</source>
+ <translation>%1에 대한 세부 정보</translation>
+ </message>
+</context>
<context>
<name>TransactionTableModel</name>
<message>
@@ -2067,22 +2675,138 @@
<source>Label</source>
<translation>라벨</translation>
</message>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>%n개의 더 많은 블록 열기</numerusform></translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>%1 까지 열림</translation>
+ </message>
+ <message>
+ <source>Offline</source>
+ <translation>오프라인</translation>
+ </message>
+ <message>
+ <source>Unconfirmed</source>
+ <translation>미확인</translation>
+ </message>
+ <message>
+ <source>Abandoned</source>
+ <translation>버려진</translation>
+ </message>
+ <message>
+ <source>Confirming (%1 of %2 recommended confirmations)</source>
+ <translation>승인 중 (권장되는 승인 회수 %2 대비 현재 승인 수 %1)</translation>
+ </message>
+ <message>
+ <source>Confirmed (%1 confirmations)</source>
+ <translation>승인됨 (%1 확인됨)</translation>
+ </message>
+ <message>
+ <source>Conflicted</source>
+ <translation>충돌</translation>
+ </message>
+ <message>
+ <source>Immature (%1 confirmations, will be available after %2)</source>
+ <translation>충분히 숙성되지 않은 상태 (%1 승인, %2 후에 사용 가능합니다)</translation>
+ </message>
+ <message>
+ <source>This block was not received by any other nodes and will probably not be accepted!</source>
+ <translation>이 블록은 다른 노드로부터 받지 않아 허용되지 않을 것임!</translation>
+ </message>
+ <message>
+ <source>Generated but not accepted</source>
+ <translation>생성되었으나 거절됨</translation>
+ </message>
<message>
<source>Received with</source>
<translation>받은 주소</translation>
</message>
<message>
+ <source>Received from</source>
+ <translation>보낸 주소</translation>
+ </message>
+ <message>
<source>Sent to</source>
<translation>보낸 주소</translation>
</message>
<message>
+ <source>Payment to yourself</source>
+ <translation>자신에게 지불</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>채굴</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>조회전용</translation>
+ </message>
+ <message>
+ <source>(n/a)</source>
+ <translation>(없음)</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(라벨 없음)</translation>
</message>
- </context>
+ <message>
+ <source>Transaction status. Hover over this field to show number of confirmations.</source>
+ <translation>거래상황. 마우스를 올리면 검증횟수가 표시됩니다.</translation>
+ </message>
+ <message>
+ <source>Date and time that the transaction was received.</source>
+ <translation>거래가 이루어진 날짜와 시각.</translation>
+ </message>
+ <message>
+ <source>Type of transaction.</source>
+ <translation>거래의 종류.</translation>
+ </message>
+ <message>
+ <source>Whether or not a watch-only address is involved in this transaction.</source>
+ <translation>조회전용 주소가 이 거래에 참여하는지 여부입니다.</translation>
+ </message>
+ <message>
+ <source>User-defined intent/purpose of the transaction.</source>
+ <translation>거래에 대한 사용자 정의 intent/purpose</translation>
+ </message>
+ <message>
+ <source>Amount removed from or added to balance.</source>
+ <translation>변경된 잔고.</translation>
+ </message>
+</context>
<context>
<name>TransactionView</name>
<message>
+ <source>All</source>
+ <translation>전체</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>오늘</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>이번주</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>이번 달</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>지난 달</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>올 해</translation>
+ </message>
+ <message>
+ <source>Range...</source>
+ <translation>범위...</translation>
+ </message>
+ <message>
<source>Received with</source>
<translation>받은 주소</translation>
</message>
@@ -2091,8 +2815,28 @@
<translation>보낸 주소</translation>
</message>
<message>
+ <source>To yourself</source>
+ <translation>자기거래</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>채굴</translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation>기타</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation>검색하기 위한 주소 또는 표 입력</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation>최소 거래액</translation>
+ </message>
+ <message>
<source>Abandon transaction</source>
- <translation>버려진 트랜잭션</translation>
+ <translation>버려진 거래</translation>
</message>
<message>
<source>Copy address</source>
@@ -2108,11 +2852,11 @@
</message>
<message>
<source>Copy transaction ID</source>
- <translation>트랜잭션 아이디 복사</translation>
+ <translation>거래 아이디 복사</translation>
</message>
<message>
<source>Copy raw transaction</source>
- <translation>로우 트랜잭션 복사</translation>
+ <translation>원시 거래 복사</translation>
</message>
<message>
<source>Copy full transaction details</source>
@@ -2140,7 +2884,7 @@
</message>
<message>
<source>Watch-only</source>
- <translation>모니터링 지갑</translation>
+ <translation>조회전용</translation>
</message>
<message>
<source>Date</source>
@@ -2266,6 +3010,18 @@
<translation>명령줄과 JSON-RPC 명령 수락</translation>
</message>
<message>
+ <source>Accept connections from outside (default: 1 if no -proxy or -connect/-noconnect)</source>
+ <translation>외부 접속을 승인합니다 (기본값 : -proxy 또는 -connect / -noconnect가 없는 경우 1)</translation>
+ </message>
+ <message>
+ <source>Connect only to the specified node(s); -noconnect or -connect=0 alone to disable automatic connections</source>
+ <translation>지정된 노드에만 연결; 자동 연결을 사용하지 않으려면 -noconnect 또는 -connect=0 을 단독으로 사용하십시오.</translation>
+ </message>
+ <message>
+ <source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
+ <translation>MIT 소프트웨어 라이센스에 따라 배포 됨, 첨부 파일 %s 또는 %s을 참조하십시오.</translation>
+ </message>
+ <message>
<source>If &lt;category&gt; is not supplied or if &lt;category&gt; = 1, output all debugging information.</source>
<translation>&lt;category&gt;가 제공되지 않거나 &lt;category&gt; = 1 인 경우, 모든 디버깅 정보를 출력</translation>
</message>
@@ -2278,10 +3034,6 @@
<translation>블록 축소: 마지막 지갑 동기화 지점이 축소된 데이터보다 과거의 것 입니다. -reindex가 필요합니다 (정지된 노드의 경우 모든 블록체인을 재다운로드합니다)</translation>
</message>
<message>
- <source>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, &gt;%u = target size in MiB to use for block files)</source>
- <translation>오래된 블록을 제거(축소)하여 디스크 용량을 줄입니다. 이 모드는 -txindex 와 -rescan 과 호환되지 않습니다. 경고: 이 모드를 취소하면 모든 블록체인을 다시 다운로드 받아야 합니다. (기본값:0 = 블록 축소 비활성화, &gt;%u = 블록파일에 사용할 용량을 MiB단위로 지정)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>블록 축소 모드에서는 재검색이 불가능 합니다. -reindex 명령을 사용해서 모든 블록체인을 다시 다운로드 해야 합니다.</translation>
</message>
@@ -2311,7 +3063,7 @@
</message>
<message>
<source>The %s developers</source>
- <translation>%s 코어 개발자</translation>
+ <translation>%s 개발자</translation>
</message>
<message>
<source>A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)</source>
@@ -2319,7 +3071,7 @@
</message>
<message>
<source>Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)</source>
- <translation>트랜잭션의 중계를 하지 않더라도 화이트 리스트에 포함된 피어에서 받은 트랜잭션은 중계하기 (기본값: %d)</translation>
+ <translation>거래의 중계를 하지 않더라도 화이트 리스트에 포함된 피어에서 받은 트랜잭션은 중계하기 (기본값: %d)</translation>
</message>
<message>
<source>Bind to given address and always listen on it. Use [host]:port notation for IPv6</source>
@@ -2331,7 +3083,7 @@
</message>
<message>
<source>Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup</source>
- <translation>시작시 모든 지갑 트랜잭션을 삭제하고 -rescan을 통하여 블록체인만 복구합니다.</translation>
+ <translation>시작시 모든 지갑 거래를 삭제하고 -rescan을 통하여 블록체인만 복구합니다.</translation>
</message>
<message>
<source>Error loading %s: You can't enable HD on a already existing non-HD wallet</source>
@@ -2346,8 +3098,16 @@
<translation>지갑 거래가 바뀌면 명령을 실행합니다.(%s 안의 명령어가 TxID로 바뀝니다)</translation>
</message>
<message>
- <source>Maximum total fees (in %s) to use in a single wallet transaction or raw transaction; setting this too low may abort large transactions (default: %s)</source>
- <translation>하나의 지갑 트랜잭션에서의 총 수수료(%s)의 최대치; 너무 낮게 설정하면 큰 트랜잭션이 중지 됩니다 (기본값: %s)</translation>
+ <source>Extra transactions to keep in memory for compact block reconstructions (default: %u)</source>
+ <translation>압축 블록 재구성을 위해 메모리에 보관해야하는 추가 거래 (기본값: %u)</translation>
+ </message>
+ <message>
+ <source>If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)</source>
+ <translation>이 블록이 체인에 있으면 해당 블록과 그 조상이 유효하며 잠재적으로 스크립트 확인을 건너 뜁니다 (0은 모두 확인, 기본값: %s, testnet: %s)</translation>
+ </message>
+ <message>
+ <source>Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)</source>
+ <translation>허용 된 최대 중간 피어 시간 오프셋 조정. 시간에 대한 지역적 전망치는 전방 또는 후방의 피어에 의해 영향을 받을 수 있습니다. (기본값: %u 초)</translation>
</message>
<message>
<source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source>
@@ -2358,6 +3118,10 @@
<translation>%s가 유용하다고 생각한다면 프로젝트에 공헌해주세요. 이 소프트웨어에 대한 보다 자세한 정보는 %s를 방문해주십시오.</translation>
</message>
<message>
+ <source>Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)</source>
+ <translation>블록 생성시 거래가 포함되도록 최저 수수료율을 설정하십시오 (%s/kB 단위). (기본값: %s)</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>
@@ -2366,6 +3130,10 @@
<translation>블록 데이터베이스에 미래의 블록이 포함되어 있습니다. 이것은 사용자의 컴퓨터의 날짜와 시간이 올바르게 설정되어 있지 않을때 나타날 수 있습니다. 만약 사용자의 컴퓨터의 날짜와 시간이 올바르다고 확신할 때에만 블록 데이터 베이스의 재구성을 하십시오</translation>
</message>
<message>
+ <source>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source>
+ <translation>출시 전의 테스트 빌드 입니다. - 스스로의 책임하에 사용하십시오 - 채굴이나 상업적 용도로 프로그램으로 사용하지 마십시오</translation>
+ </message>
+ <message>
<source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source>
<translation>데이터베이스를 포크 전 상태로 돌리지 못했습니다. 블록체인을 다시 다운로드 해주십시오.</translation>
</message>
@@ -2374,8 +3142,24 @@
<translation>리슨(Listen) 포트를 할당하기 위해 UPnP 사용 (기본값: 열려있거나 -proxy 옵션을 사용하지 않을 시 1)</translation>
</message>
<message>
+ <source>Username and hashed password for JSON-RPC connections. The field &lt;userpw&gt; comes in the format: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=&lt;USERNAME&gt;/rpcpassword=&lt;PASSWORD&gt; pair of arguments. This option can be specified multiple times</source>
+ <translation>클라이언트JSON-RPC 연결시 사용자 이름과 해시화된 암호문. &lt;userpw&gt; 필드는 &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt; 포멧으로 구성되어 있습니다. 전형적 파이썬 스크립트에선 share/rpcuser가 포함되어 있습니다. 그런 다음 클라이언트는 rpcuser=&lt;USERNAME&gt;/ rpcpassword=&lt;PASSWORD&gt; 쌍의 인수를 사용하여 정상적으로 연결합니다. 이 옵션은 여러번 지정할 수 있습니다.</translation>
+ </message>
+ <message>
+ <source>Wallet will not create transactions that violate mempool chain limits (default: %u)</source>
+ <translation>지갑은 mempool chain limit (기본값: %u) 을 위반하는 거래를 생성하지 않습니다.</translation>
+ </message>
+ <message>
+ <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
+ <translation>경고 : 모든 네트워크가 동의해야 하나, 일부 채굴자들에게 문제가 있는 것으로 보입니다. </translation>
+ </message>
+ <message>
+ <source>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source>
+ <translation>경고: 현재 비트코인 버전이 다른 네트워크 참여자들과 동일하지 않은 것 같습니다. 당신 또는 다른 참여자들이 동일한 비트코인 버전으로 업그레이드 할 필요가 있습니다.</translation>
+ </message>
+ <message>
<source>You need to rebuild the database using -reindex-chainstate to change -txindex</source>
- <translation>-txindex를 바꾸기 위해서는 -reindex-chainstate를 사용해서 데이터베이스를 재구성해야 합니다. </translation>
+ <translation>-txindex를 바꾸기 위해서는 -reindex-chainstate 를 사용해서 데이터베이스를 재구성해야 합니다. </translation>
</message>
<message>
<source>%s corrupt, salvage failed</source>
@@ -2406,6 +3190,14 @@
<translation>%s 주소를 확인할 수 없습니다: '%s'</translation>
</message>
<message>
+ <source>Chain selection options:</source>
+ <translation>체인 선택 옵션:</translation>
+ </message>
+ <message>
+ <source>Change index out of range</source>
+ <translation>범위 밖의 인덱스 변경</translation>
+ </message>
+ <message>
<source>Connection options:</source>
<translation>연결 설정 : </translation>
</message>
@@ -2427,7 +3219,7 @@
</message>
<message>
<source>Do you want to rebuild the block database now?</source>
- <translation>블락 데이터베이스를 다시 생성하시겠습니까?</translation>
+ <translation>블록 데이터베이스를 다시 생성하시겠습니까?</translation>
</message>
<message>
<source>Enable publish hash block in &lt;address&gt;</source>
@@ -2435,19 +3227,19 @@
</message>
<message>
<source>Enable publish hash transaction in &lt;address&gt;</source>
- <translation>&lt;address&gt;에 대한 해시 트랙잭션 공개 활성화</translation>
+ <translation>&lt;address&gt;에 대한 해시 거래 공개 활성화</translation>
</message>
<message>
<source>Enable publish raw block in &lt;address&gt;</source>
- <translation>&lt;address&gt;에 대한 로우 블록 공개 활성화</translation>
+ <translation>&lt;address&gt;에 대한 원시 블록 공개 활성화</translation>
</message>
<message>
<source>Enable publish raw transaction in &lt;address&gt;</source>
- <translation>&lt;address&gt;에 대한 로우 트랜잭션 공개 활성화</translation>
+ <translation>&lt;address&gt;에 대한 원시 거래 공개 활성화</translation>
</message>
<message>
<source>Enable transaction replacement in the memory pool (default: %u)</source>
- <translation>메모리 풀(pool) 내의 트랜잭션 치환(replacement) 활성화 (기본값: %u)</translation>
+ <translation>메모리 풀(pool) 내의 거래 치환(replacement) 활성화 (기본값: %u)</translation>
</message>
<message>
<source>Error initializing block database</source>
@@ -2515,7 +3307,7 @@
</message>
<message>
<source>Keep the transaction memory pool below &lt;n&gt; megabytes (default: %u)</source>
- <translation>트랜잭션 메모리 풀의 용량을 &lt;n&gt;메가바이트 아래로 유지하기 (기본값: %u)</translation>
+ <translation>거래 메모리 풀의 용량을 &lt;n&gt;메가바이트 아래로 유지하기 (기본값: %u)</translation>
</message>
<message>
<source>Loading banlist...</source>
@@ -2598,6 +3390,10 @@
<translation>리슨(Listen) 포트를 할당하기 위해 UPnP 사용 (기본값: %u)</translation>
</message>
<message>
+ <source>Use the test chain</source>
+ <translation>테스트 체인 사용</translation>
+ </message>
+ <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation>사용자 정의 코멘트 (%s)에 안전하지 못한 글자가 포함되어 있습니다.</translation>
</message>
@@ -2655,7 +3451,7 @@
</message>
<message>
<source>Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)</source>
- <translation>해당 금액(%s/kB) 보다 적은 수수료는 중계, 채굴, 트랜잭션 생성에서 수수료 면제로 간주됩니다 (기본값: %s)</translation>
+ <translation>해당 금액(%s/kB) 보다 적은 수수료는 중계, 채굴, 거래 생성에서 수수료 면제로 간주됩니다 (기본값: %s)</translation>
</message>
<message>
<source>If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)</source>
@@ -2663,11 +3459,11 @@
</message>
<message>
<source>Invalid amount for -maxtxfee=&lt;amount&gt;: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)</source>
- <translation>유효하지 않은 금액 -maxtxfee=&lt;amount&gt;: '%s' (트랜잭션이 막히는 상황을 방지하게 위해 적어도 %s 의 중계 수수료를 지정해야 합니다)</translation>
+ <translation>유효하지 않은 금액 -maxtxfee=&lt;amount&gt;: '%s' (거래가 막히는 상황을 방지하게 위해 적어도 %s 의 중계 수수료를 지정해야 합니다)</translation>
</message>
<message>
<source>Maximum size of data in data carrier transactions we relay and mine (default: %u)</source>
- <translation>중계 및 채굴을 할 때 데이터 운송 트랜잭션에서 데이터의 최대 크기 (기본값: %u)</translation>
+ <translation>중계 및 채굴을 할 때 데이터 운송 거래에서 데이터의 최대 크기 (기본값: %u)</translation>
</message>
<message>
<source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
@@ -2682,8 +3478,12 @@
<translation>거래액이 수수료를 지불하기엔 너무 작습니다</translation>
</message>
<message>
+ <source>Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start</source>
+ <translation>BIP32 이후에는 계층적 결정성 키 생성 (HD)을 사용하십시오. 지갑 생성/처음 시작 시에만 효과가 있습니다.</translation>
+ </message>
+ <message>
<source>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</source>
- <translation>화이트리스트에 포함된 피어는 이미 메모리풀에 포함되어 있어도 DoS 추방이 되지 않으며 그들의 트랜잭션이 항상 중계됩니다, 이는 예를 들면 게이트웨이에서 유용합니다.</translation>
+ <translation>화이트리스트에 포함된 피어는 이미 메모리풀에 포함되어 있어도 DoS 추방이 되지 않으며 그들의 거래가 항상 중계됩니다, 이는 예를 들면 게이트웨이에서 유용합니다.</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>
@@ -2727,7 +3527,7 @@
</message>
<message>
<source>Keep at most &lt;n&gt; unconnectable transactions in memory (default: %u)</source>
- <translation>최대 &lt;n&gt;개의 연결할 수 없는 트랜잭션을 메모리에 저장 (기본값: %u)</translation>
+ <translation>최대 &lt;n&gt;개의 연결할 수 없는 거래를 메모리에 저장 (기본값: %u)</translation>
</message>
<message>
<source>Need to specify a port with -whitebind: '%s'</source>
@@ -2747,7 +3547,7 @@
</message>
<message>
<source>Rescan the block chain for missing wallet transactions on startup</source>
- <translation>시작시 누락된 지갑 트랜잭션에 대해 블록 체인을 다시 검색 합니다</translation>
+ <translation>시작시 누락된 지갑 거래에 대해 블록 체인을 다시 검색 합니다</translation>
</message>
<message>
<source>Send trace/debug info to console instead of debug.log file</source>
@@ -2755,7 +3555,7 @@
</message>
<message>
<source>Send transactions as zero-fee transactions if possible (default: %u)</source>
- <translation>가능한 경우 수수료 없이 트랜잭션 보내기 (기본값: %u)</translation>
+ <translation>가능한 경우 수수료 없이 거래 보내기 (기본값: %u)</translation>
</message>
<message>
<source>Show all debugging options (usage: --help -help-debug)</source>
@@ -2791,7 +3591,7 @@
</message>
<message>
<source>Transaction too large for fee policy</source>
- <translation>수수료 정책에 비해 트랜잭션이 너무 큽니다</translation>
+ <translation>수수료 정책에 비해 거래가 너무 큽니다</translation>
</message>
<message>
<source>Transaction too large</source>
@@ -2831,7 +3631,7 @@
</message>
<message>
<source>Execute command when the best block changes (%s in cmd is replaced by block hash)</source>
- <translation>최고의 블럭이 변하면 명령을 실행(cmd 에 있는 %s 는 블럭 해시에 의해 대체되어 짐)</translation>
+ <translation>최고의 블록이 변하면 명령을 실행 (cmd 에 있는 %s 는 블록 해시에 의해 대체되어 짐)</translation>
</message>
<message>
<source>Allow DNS lookups for -addnode, -seednode and -connect</source>
@@ -2843,27 +3643,35 @@
</message>
<message>
<source>(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)</source>
- <translation>(1 = 트랜잭션의 메타 데이터를 유지함 예. 계좌정보 와 지불 요구 정보, 2 = 트랜잭션 메타 데이터 파기)</translation>
+ <translation>(1 = 거래의 메타 데이터를 유지함 예. 계좌정보 와 지불 요구 정보, 2 = 거래 메타 데이터 파기)</translation>
</message>
<message>
<source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
- <translation>-maxtxfee값이 너무 큽니다! 하나의 트랜잭션에 너무 큰 수수료가 지불 됩니다.</translation>
+ <translation>-maxtxfee값이 너무 큽니다! 하나의 거래에 너무 큰 수수료가 지불 됩니다.</translation>
</message>
<message>
<source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
- <translation>메모리 풀에 있는 트랜잭션 기록을 &lt;n&gt;시간 후 부터는 유지하지 않기 (기본값: %u)</translation>
+ <translation>메모리 풀에 있는 거래 기록을 &lt;n&gt;시간 후 부터는 유지하지 않기 (기본값: %u)</translation>
+ </message>
+ <message>
+ <source>Equivalent bytes per sigop in transactions for relay and mining (default: %u)</source>
+ <translation>릴레이 및 마이닝 거래의 sigop 당 동등한 바이트 (기본값: %u)</translation>
</message>
<message>
<source>Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)</source>
<translation>해당 금액(%s/kB) 보다 적은 수수료는 수수료 면제로 간주됩니다.(기본값: %s)</translation>
</message>
<message>
+ <source>Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)</source>
+ <translation>피어들이 로컬 중계 정책을 위반하더라도 화이트 리스트에 포함된 피어인경우 강제로 중계하기 (기본값: %d)</translation>
+ </message>
+ <message>
<source>How thorough the block verification of -checkblocks is (0-4, default: %u)</source>
<translation>-checkblocks을 통한 블록 점검 (0-4, 기본값: %u)</translation>
</message>
<message>
<source>Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)</source>
- <translation>getrawtransaction를 RPC CALL를 통해 완전한 트랜잭션 인덱스 유지 (기본값: %u)</translation>
+ <translation>getrawtransaction를 RPC CALL를 통해 완전한 거래 인덱스 유지 (기본값: %u)</translation>
</message>
<message>
<source>Number of seconds to keep misbehaving peers from reconnecting (default: %u)</source>
@@ -2874,8 +3682,24 @@
<translation>디버그 정보 출력 (기본값: %u, &lt;category&gt; 제공은 선택입니다)</translation>
</message>
<message>
+ <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect/-noconnect)</source>
+ <translation>보유한 피어 주소가 적은 경우 DNS 조회를 통해 피어 주소를 요청합니다. (-connect / -noconnect가 아니라면 기본값은 1)</translation>
+ </message>
+ <message>
+ <source>Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(1) (default: %d)</source>
+ <translation>non-segwit(0) 또는 segwit(1) (기본값: %d) 가 아닌 자세한 정보 표시 모드로 반환 된 원시 거래 또는 블록 hex의 직렬화를 설정합니다.</translation>
+ </message>
+ <message>
<source>Support filtering of blocks and transaction with bloom filters (default: %u)</source>
- <translation>블룸필터를 통해 블록과 트랜잭션 필터링 지원 (기본값: %u)</translation>
+ <translation>블룸필터를 통해 블록과 거래 필터링 지원 (기본값: %u)</translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you may pay when fee estimates are not available.</source>
+ <translation>이것은 수수료 견적을 이용할 수 없을 때 지불 할 수 있는 거래 수수료입니다.</translation>
+ </message>
+ <message>
+ <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit %s and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
+ <translation>이 제품에는 OpenSSL Project에서 OpenSSL Toolkit %s으로 사용하기 위해 개발 한 소프트웨어와 Eric Young이 작성한 암호화 소프트웨어 및 Thomas Bernard가 작성한 UPnP 소프트웨어가 포함되어 있습니다.</translation>
</message>
<message>
<source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source>
@@ -2910,6 +3734,10 @@
<translation>설정된 IP주소 (보기 1.2.3.4) 혹은 CIDR로 작성된 네트워크 (보기 1.2.3.0/24)로 화이트리스트에 포함된 피어에 접속합니다. 이 설정은 복수로 지정 할 수 있습니다.</translation>
</message>
<message>
+ <source>%s is set very high!</source>
+ <translation>%s가 매우 높게 설정되었습니다!</translation>
+ </message>
+ <message>
<source>(default: %s)</source>
<translation>(기본값: %s)</translation>
</message>
@@ -2930,6 +3758,10 @@
<translation>잘못된 -proxy 주소입니다: '%s'</translation>
</message>
<message>
+ <source>Keypool ran out, please call keypoolrefill first</source>
+ <translation>Keypool이 종료되었습니다. 먼저 keypoolrefill을 호출하십시오.</translation>
+ </message>
+ <message>
<source>Listen for JSON-RPC connections on &lt;port&gt; (default: %u or testnet: %u)</source>
<translation>JSON-RPC 연결을 &lt;port&gt;포트로 받기 (기본값: %u 혹은 테스트넷: %u)</translation>
</message>
@@ -2943,7 +3775,7 @@
</message>
<message>
<source>Make the wallet broadcast transactions</source>
- <translation>지갑 브로드캐스트 트랜잭션을 만들기</translation>
+ <translation>지갑 브로드캐스트 거래를 만들기</translation>
</message>
<message>
<source>Maximum per-connection receive buffer, &lt;n&gt;*1000 bytes (default: %u)</source>
@@ -2959,17 +3791,25 @@
</message>
<message>
<source>Relay and mine data carrier transactions (default: %u)</source>
- <translation>데이터 운송 트랜잭션을 중계 및 채굴 (기본값: %u)</translation>
+ <translation>데이터 운송 거래를 중계 및 채굴 (기본값: %u)</translation>
</message>
<message>
<source>Relay non-P2SH multisig (default: %u)</source>
<translation>비 P2SH 다중서명을 중계 (기본값: %u)</translation>
</message>
<message>
+ <source>Send transactions with full-RBF opt-in enabled (default: %u)</source>
+ <translation>full-RBF opt-in이 활성화 된 거래을 전송합니다. (기본값: %u)</translation>
+ </message>
+ <message>
<source>Set key pool size to &lt;n&gt; (default: %u)</source>
<translation>키 풀 사이즈를 &lt;n&gt; 로 설정 (기본값: %u)</translation>
</message>
<message>
+ <source>Set maximum BIP141 block weight (default: %d)</source>
+ <translation>최대 BIP141 블록 무게 설정 (기본값: %d)</translation>
+ </message>
+ <message>
<source>Set the number of threads to service RPC calls (default: %d)</source>
<translation>원격 프로시져 호출 서비스를 위한 쓰레드 개수를 설정 (기본값 : %d)</translation>
</message>
@@ -2987,15 +3827,39 @@
</message>
<message>
<source>Spend unconfirmed change when sending transactions (default: %u)</source>
- <translation>트랜잭션을 보낼 때 검증되지 않은 잔돈 쓰기 (기본값: %u)</translation>
+ <translation>거래를 보낼 때 검증되지 않은 잔돈 쓰기 (기본값: %u)</translation>
</message>
<message>
<source>Starting network threads...</source>
<translation>네트워크 스레드 시작중...</translation>
</message>
<message>
+ <source>The wallet will avoid paying less than the minimum relay fee.</source>
+ <translation>지갑은 최소 중계 수수료보다 적은 금액을 지불하는 것을 피할 것입니다.</translation>
+ </message>
+ <message>
+ <source>This is the minimum transaction fee you pay on every transaction.</source>
+ <translation>이것은 모든 거래에서 지불하는 최소 거래 수수료입니다.</translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you will pay if you send a transaction.</source>
+ <translation>이것은 거래를 보낼 경우 지불 할 거래 수수료입니다.</translation>
+ </message>
+ <message>
<source>Threshold for disconnecting misbehaving peers (default: %u)</source>
- <translation>이상행동 네트워크 참여자의 연결을 차단시키기 위한 한계치 (기본값: %u)</translation>
+ <translation>비정상적인 피어의 연결을 차단시키기 위한 임계값 (기본값: %u)</translation>
+ </message>
+ <message>
+ <source>Transaction amounts must not be negative</source>
+ <translation>거래액은 반드시 정수여야합니다.</translation>
+ </message>
+ <message>
+ <source>Transaction has too long of a mempool chain</source>
+ <translation>거래가 너무 긴 mempool 체인을 갖고 있습니다</translation>
+ </message>
+ <message>
+ <source>Transaction must have at least one recipient</source>
+ <translation>거래에는 최소한 한명의 수령인이 있어야 합니다.</translation>
</message>
<message>
<source>Unknown network specified in -onlynet: '%s'</source>
@@ -3007,7 +3871,7 @@
</message>
<message>
<source>Loading block index...</source>
- <translation>블럭 인덱스를 불러오는 중...</translation>
+ <translation>블록 인덱스를 불러오는 중...</translation>
</message>
<message>
<source>Add a node to connect to and attempt to keep the connection open</source>
diff --git a/src/qt/locale/bitcoin_la.ts b/src/qt/locale/bitcoin_la.ts
index 3b67fa1e74..d84dd7e4e2 100644
--- a/src/qt/locale/bitcoin_la.ts
+++ b/src/qt/locale/bitcoin_la.ts
@@ -194,10 +194,6 @@
<translation>Optiones mandati initiantis</translation>
</message>
<message>
- <source>No block source available...</source>
- <translation>Nulla fons frustorum absens...</translation>
- </message>
- <message>
<source>%1 behind</source>
<translation>%1 post</translation>
</message>
diff --git a/src/qt/locale/bitcoin_lv_LV.ts b/src/qt/locale/bitcoin_lv_LV.ts
index 750e0ff28d..2953da443a 100644
--- a/src/qt/locale/bitcoin_lv_LV.ts
+++ b/src/qt/locale/bitcoin_lv_LV.ts
@@ -230,10 +230,6 @@
<translation>&amp;Komandrindas iespējas</translation>
</message>
<message>
- <source>No block source available...</source>
- <translation>Nav pieejams neviens bloku avots...</translation>
- </message>
- <message>
<source>%1 behind</source>
<translation>%1 aizmugurē</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ms_MY.ts b/src/qt/locale/bitcoin_ms_MY.ts
index 0108332dd7..7844093e3b 100644
--- a/src/qt/locale/bitcoin_ms_MY.ts
+++ b/src/qt/locale/bitcoin_ms_MY.ts
@@ -2,6 +2,10 @@
<context>
<name>AddressBookPage</name>
<message>
+ <source>Right-click to edit address or label</source>
+ <translation>Klik-kanan untuk edit alamat ataupun label</translation>
+ </message>
+ <message>
<source>Create a new address</source>
<translation>Cipta alamat baru</translation>
</message>
@@ -18,6 +22,10 @@
<translation>&amp;Salin</translation>
</message>
<message>
+ <source>C&amp;lose</source>
+ <translation>&amp;Tutup</translation>
+ </message>
+ <message>
<source>Delete the currently selected address from the list</source>
<translation>Padam alamat semasa yang dipilih dari senaraiyang dipilih dari senarai</translation>
</message>
@@ -34,25 +42,301 @@ Alihkan fail data ke dalam tab semasa</translation>
<source>&amp;Delete</source>
<translation>&amp;Padam</translation>
</message>
- </context>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Pilih alamat untuk hantar koin kepada</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Pilih alamat untuk menerima koin dengan</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>&amp;Pilih</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>alamat-alamat penghantaran</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>alamat-alamat penerimaan</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>Ini adalah alamat Bitcoin anda untuk pembayaran. Periksa jumlah dan alamat penerima sebelum membuat penghantaran koin sentiasa.</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>Ini adalah alamat Bitcoin anda untuk menerima pembayaraan. Anda disyorkan untuk menguna alamat menerima untuk setiap transaksi.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Salin Aamat</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Salin &amp; Label</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Edit</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Eskport Senarai Alamat</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Fail dibahagi oleh koma(*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Mengeksport Gagal</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Terdapat ralat semasa cubaan menyimpan senarai alamat kepada %1. Sila cuba lagi.</translation>
+ </message>
+</context>
<context>
<name>AddressTableModel</name>
- </context>
+ <message>
+ <source>Label</source>
+ <translation>Label</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Alamat</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(tiada label)</translation>
+ </message>
+</context>
<context>
<name>AskPassphraseDialog</name>
- </context>
+ <message>
+ <source>Passphrase Dialog</source>
+ <translation>Dialog frasa laluan</translation>
+ </message>
+ <message>
+ <source>Enter passphrase</source>
+ <translation>memasukkan frasa laluan</translation>
+ </message>
+ <message>
+ <source>New passphrase</source>
+ <translation>Frasa laluan baru</translation>
+ </message>
+ <message>
+ <source>Repeat new passphrase</source>
+ <translation>Ulangi frasa laluan baru</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>Memasukkan frasa laluan baru kepada dompet.&lt;br/&gt;Sila mengunakkan frasa laluan yang&lt;b&gt;mengandungi 10 atau lebih aksara rawak&lt;/b&gt;,ataupun&lt;b&gt;lapan atau lebih perkataan.&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Dompet encrypt</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Operasi ini perlukan frasa laluan dompet anda untuk membuka kunci dompet.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Membuka kunci dompet</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Operasi ini memerlukan frasa laluan dompet anda untuk menyahsulit dompet.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Menyahsulit dompet</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Menukar frasa laluan</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Memasukkan frasa laluan lama dan frasa laluan baru untuk.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Mengesahkan enkripsi dompet</translation>
+ </message>
+ <message>
+ <source>Warning: If you encrypt your wallet and lose your passphrase, you will &lt;b&gt;LOSE ALL OF YOUR BITCOINS&lt;/b&gt;!</source>
+ <translation>Amaran: Jika anda enkripkan dompet anda dan hilangkan frasa laluan, anda akan &lt;b&gt;ANDA AKAN HILANGKAN SEMUA BITCOIN ANDA&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Anda pasti untuk membuat enkripsi dompet anda?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Dompet dienkripsi</translation>
+ </message>
+ <message>
+ <source>%1 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>%1 akan tutup untuk menyelesaikan proses enkripsi. Ingat bahawa enkripsi tidak boleh melidungi sepenuhnya bitcoins anda daripada dicuri oleh malware yang menjangkiti komputer anda.</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>PENTING: Apa-apa sandaran yang anda buat sebelum ini untuk fail dompet anda hendaklah digantikan dengan fail dompet enkripsi yang dijana baru. Untuk sebab-sebab keselamatan , sandaran fail dompet yang belum dibuat enkripsi sebelum ini akan menjadi tidak berguna secepat anda mula guna dompet enkripsi baru.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Enkripsi dompet gagal</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Enkripsi dompet gagal kerana ralat dalaman. Dompet anda tidak dienkripkan.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>Frasa laluan yang dibekalkan tidak sepadan.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Pembukaan kunci dompet gagal</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>Frasa laluan dimasukki untuk dekripsi dompet adalah tidak betul.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Dekripsi dompet gagal</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>Frasa laluan dompet berjaya ditukar.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Amaran: Kunci Caps Lock buka!</translation>
+ </message>
+</context>
<context>
<name>BanTableModel</name>
- </context>
+ <message>
+ <source>IP/Netmask</source>
+ <translation>IP/Netmask</translation>
+ </message>
+ <message>
+ <source>Banned Until</source>
+ <translation>Diharamkan sehingga</translation>
+ </message>
+</context>
<context>
<name>BitcoinGUI</name>
<message>
+ <source>Sign &amp;message...</source>
+ <translation>Tandatangan &amp; mesej...</translation>
+ </message>
+ <message>
+ <source>Synchronizing with network...</source>
+ <translation>Penyegerakan dengan rangkaian...</translation>
+ </message>
+ <message>
+ <source>&amp;Overview</source>
+ <translation>&amp;Gambaran Keseluruhan</translation>
+ </message>
+ <message>
+ <source>Node</source>
+ <translation>Nod</translation>
+ </message>
+ <message>
+ <source>Show general overview of wallet</source>
+ <translation>Tunjuk gambaran keseluruhan umum dompet</translation>
+ </message>
+ <message>
+ <source>&amp;Transactions</source>
+ <translation>&amp;Transaksi</translation>
+ </message>
+ <message>
+ <source>Browse transaction history</source>
+ <translation>Menyemak imbas sejarah transaksi </translation>
+ </message>
+ <message>
+ <source>E&amp;xit</source>
+ <translation>&amp;Keluar</translation>
+ </message>
+ <message>
+ <source>Quit application</source>
+ <translation>Berhenti aplikasi</translation>
+ </message>
+ <message>
+ <source>&amp;About %1</source>
+ <translation>&amp;Mengenai%1</translation>
+ </message>
+ <message>
+ <source>Show information about %1</source>
+ <translation>Menunjuk informasi mengenai%1</translation>
+ </message>
+ <message>
+ <source>About &amp;Qt</source>
+ <translation>Mengenai &amp;Qt</translation>
+ </message>
+ <message>
+ <source>Show information about Qt</source>
+ <translation>Menunjuk informasi megenai Qt</translation>
+ </message>
+ <message>
<source>&amp;Options...</source>
<translation>Pilihan</translation>
</message>
+ <message>
+ <source>Modify configuration options for %1</source>
+ <translation>Mengubah suai pilihan konfigurasi untuk %1</translation>
+ </message>
+ <message>
+ <source>&amp;Encrypt Wallet...</source>
+ <translation>&amp;Enkripsi Dompet</translation>
+ </message>
+ <message>
+ <source>&amp;Backup Wallet...</source>
+ <translation>&amp;Dompet Sandaran...</translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase...</source>
+ <translation>&amp;Menukar frasa-laluan</translation>
+ </message>
+ <message>
+ <source>&amp;Sending addresses...</source>
+ <translation>&amp;Menghantar frasa-laluan</translation>
+ </message>
+ <message>
+ <source>&amp;Receiving addresses...</source>
+ <translation>&amp;Menerima frasa-laluan...</translation>
+ </message>
+ <message>
+ <source>Open &amp;URI...</source>
+ <translation>Buka &amp;URI...</translation>
+ </message>
+ <message>
+ <source>Reindexing blocks on disk...</source>
+ <translation>Reindexi blok pada cakera...</translation>
+ </message>
+ <message>
+ <source>Send coins to a Bitcoin address</source>
+ <translation>Menghantar koin kepada alamat Bitcoin</translation>
+ </message>
+ <message>
+ <source>Backup wallet to another location</source>
+ <translation>Wallet sandaran ke lokasi lain</translation>
+ </message>
</context>
<context>
<name>CoinControlDialog</name>
+ <message>
+ <source>(no label)</source>
+ <translation>(tiada label)</translation>
+ </message>
</context>
<context>
<name>EditAddressDialog</name>
@@ -113,9 +397,25 @@ Alihkan fail data ke dalam tab semasa</translation>
<source>Copy &amp;Address</source>
<translation>&amp;Salin Alamat</translation>
</message>
+ <message>
+ <source>Address</source>
+ <translation>Alamat</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Label</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Label</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(tiada label)</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -123,7 +423,11 @@ Alihkan fail data ke dalam tab semasa</translation>
<source>Balance:</source>
<translation>Baki</translation>
</message>
- </context>
+ <message>
+ <source>(no label)</source>
+ <translation>(tiada label)</translation>
+ </message>
+</context>
<context>
<name>SendCoinsEntry</name>
</context>
@@ -150,9 +454,33 @@ Alihkan fail data ke dalam tab semasa</translation>
</context>
<context>
<name>TransactionTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Label</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(tiada label)</translation>
+ </message>
</context>
<context>
<name>TransactionView</name>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Fail dibahagi oleh koma(*.csv)</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Label</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Alamat</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Mengeksport Gagal</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
diff --git a/src/qt/locale/bitcoin_nb.ts b/src/qt/locale/bitcoin_nb.ts
index f98cdd32d2..14919c440d 100644
--- a/src/qt/locale/bitcoin_nb.ts
+++ b/src/qt/locale/bitcoin_nb.ts
@@ -41,10 +41,78 @@
<source>&amp;Delete</source>
<translation>&amp;Slett</translation>
</message>
- </context>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Velg adressen å sende mynter til</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Velg adressen til å motta mynter med</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>V&amp;elg</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Utsendingsadresser</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Mottaksadresser</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>Dette er dine Bitcoin-adresser for sending av betalinger. Sjekk alltid beløpet og mottakeradressen før sending av mynter.</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>Dette er dine Bitcoin-adresser for å sende betalinger med. Det er anbefalt å bruke en ny mottaksadresse for hver transaksjon.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Kopier Adresse</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Kopier &amp;Merkelapp</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Rediger</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Eksporter adresseliste</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Kommaseparert fil (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Eksportering feilet</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Det oppstod en feil under lagring av adresselisten til %1. Vennligst prøv på nytt.</translation>
+ </message>
+</context>
<context>
<name>AddressTableModel</name>
- </context>
+ <message>
+ <source>Label</source>
+ <translation>Merkelapp</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adresse</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(ingen merkelapp)</translation>
+ </message>
+</context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -63,7 +131,95 @@
<source>Repeat new passphrase</source>
<translation>Gjenta ny adgangsfrase</translation>
</message>
- </context>
+ <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>Oppgi adgangsfrasen til lommeboken.&lt;br/&gt;Vennligst bruk en adgangsfrase med &lt;b&gt;ti eller flere tilfeldige tegn&lt;/b&gt;, eller &lt;b&gt;åtte eller flere ord&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Krypter lommebok</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Denne operasjonen krever adgangsfrasen til lommeboken for å låse den opp.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Lås opp lommebok</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Denne operasjonen krever adgangsfrasen til lommeboken for å dekryptere den.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Dekrypter lommebok</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Endre adgangsfrase</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Angi den gamle og en ny adgangsfrase til lommeboken.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Bekreft kryptering av lommebok</translation>
+ </message>
+ <message>
+ <source>Warning: If you encrypt your wallet and lose your passphrase, you will &lt;b&gt;LOSE ALL OF YOUR BITCOINS&lt;/b&gt;!</source>
+ <translation>Advarsel: Hvis du krypterer lommeboken og mister adgangsfrasen, så vil du &lt;b&gt;MISTE ALLE DINE BITCOINS&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Er du sikker på at du vil kryptere lommeboken?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Lommebok kryptert</translation>
+ </message>
+ <message>
+ <source>%1 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>%1 vil nå lukkes for å fullføre krypteringsprosessen. Husk at kryptering av lommeboken ikke fullt ut kan beskytte dine bitcoins fra å bli stjålet om skadevare infiserer datamaskinen din.</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>VIKTIG: Tidligere sikkerhetskopier av din lommebokfil bør erstattes med den nylig genererte og krypterte filen, da de blir ugyldiggjort av sikkerhetshensyn så snart du begynner å bruke den nye krypterte lommeboken.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Kryptering av lommebok feilet</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Kryptering av lommebok feilet på grunn av en intern feil. Din lommebok ble ikke kryptert.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>De angitte adgangsfrasene er ulike.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Opplåsing av lommebok feilet</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>Adgangsfrasen angitt for dekryptering av lommeboken var feil.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Dekryptering av lommebok feilet</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>Adgangsfrase for lommebok er endret.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Advarsel: Caps Lock er på!</translation>
+ </message>
+</context>
<context>
<name>BanTableModel</name>
<message>
@@ -162,6 +318,18 @@
<translation>Åpne &amp;URI...</translation>
</message>
<message>
+ <source>Click to disable network activity.</source>
+ <translation>Klikk for å deaktivere nettverksaktivitet</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>Nettverksaktivitet deaktivert</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>Klikk for å aktivere nettverksaktivitet igjen.</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>Reindekserer blokker på harddisk...</translation>
</message>
@@ -265,10 +433,6 @@
<source>%n active connection(s) to Bitcoin network</source>
<translation><numerusform>%n aktiv forbindelse til Bitcoin-nettverket</numerusform><numerusform>%n aktive forbindelser til Bitcoin-nettverket</numerusform></translation>
</message>
- <message>
- <source>No block source available...</source>
- <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>
@@ -306,6 +470,10 @@
<translation>%1 klient</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>Kobler til likemannsnettverket...</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>Laster ned...</translation>
</message>
@@ -355,7 +523,11 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Lommeboken er &lt;b&gt;kryptert&lt;/b&gt; og for tiden &lt;b&gt;låst&lt;/b&gt;</translation>
</message>
- </context>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>En fatal feil har inntruffet. Bitcoin kan ikke lenger trygt fortsette, og må derfor avslutte.</translation>
+ </message>
+</context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -426,7 +598,59 @@
<source>Confirmed</source>
<translation>Bekreftet</translation>
</message>
- </context>
+ <message>
+ <source>Copy address</source>
+ <translation>Kopier adresse</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopier beløp</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Kopier transaksjons-ID</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Kopier mengde</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Kopier gebyr</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Kopier veksel</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation>(%1 låst)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>ja</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>nei</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation>Kan variere +/- %1 satoshi(er) per input.</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(ingen merkelapp)</translation>
+ </message>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation>veksel fra %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(veksel)</translation>
+ </message>
+</context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -449,7 +673,31 @@
<source>&amp;Address</source>
<translation>&amp;Adresse</translation>
</message>
- </context>
+ <message>
+ <source>New receiving address</source>
+ <translation>Ny mottaksadresse</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Ny utsendingsadresse</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Rediger mottaksadresse</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Rediger utsendingsadresse</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Kunne ikke låse opp lommebok.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Generering av ny nøkkel feilet.</translation>
+ </message>
+</context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -523,7 +771,11 @@
<source>Show splash screen on startup (default: %u)</source>
<translation>Vis velkomstbilde ved oppstart (default: %u)</translation>
</message>
- </context>
+ <message>
+ <source>Reset all settings changed in the GUI</source>
+ <translation>Nullstill alle innstillinger endret i det grafiske brukergrensesnittet</translation>
+ </message>
+</context>
<context>
<name>Intro</name>
<message>
@@ -566,10 +818,30 @@
<translation>Skjema</translation>
</message>
<message>
+ <source>Unknown...</source>
+ <translation>Ukjent...</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation>Tidspunkt for siste blokk</translation>
</message>
<message>
+ <source>Progress</source>
+ <translation>Fremgang</translation>
+ </message>
+ <message>
+ <source>Progress increase per hour</source>
+ <translation>Fremgangen stiger hver time</translation>
+ </message>
+ <message>
+ <source>calculating...</source>
+ <translation>kalkulerer...</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation>Estimert gjenstående tid før ferdig synkronisert</translation>
+ </message>
+ <message>
<source>Hide</source>
<translation>Skjul</translation>
</message>
@@ -740,6 +1012,10 @@
<translation>&amp;Vindu</translation>
</message>
<message>
+ <source>&amp;Hide the icon from the system tray.</source>
+ <translation>&amp;Skjul ikonet fra oppgavelinjen.</translation>
+ </message>
+ <message>
<source>Hide tray icon</source>
<translation>Skjul søppel ikon</translation>
</message>
@@ -939,17 +1215,61 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation><numerusform>%n sekund</numerusform><numerusform>%n sekunder</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation><numerusform>%n minutt</numerusform><numerusform>%n minutter</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation><numerusform>%n time</numerusform><numerusform>%n timer</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation><numerusform>%n dag</numerusform><numerusform>%n dager</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation><numerusform>%n uke</numerusform><numerusform>%n uker</numerusform></translation>
+ </message>
<message>
<source>%1 and %2</source>
<translation>%1 og %2</translation>
</message>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation><numerusform>%n år</numerusform><numerusform>%n år</numerusform></translation>
+ </message>
</context>
<context>
<name>QObject::QObject</name>
- </context>
+ <message>
+ <source>Error: %1</source>
+ <translation>Feil: %1</translation>
+ </message>
+</context>
<context>
<name>QRImageWidget</name>
- </context>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;Lagre bilde...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>&amp;Kopier bilde</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>Lagre QR-kode</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>PNG-bilde (*.png)</translation>
+ </message>
+</context>
<context>
<name>RPCConsole</name>
<message>
@@ -1287,7 +1607,11 @@
<source>Remove</source>
<translation>Fjern</translation>
</message>
- </context>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopier beløp</translation>
+ </message>
+</context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -1306,9 +1630,37 @@
<source>&amp;Save Image...</source>
<translation>&amp;Lagre Bilde...</translation>
</message>
+ <message>
+ <source>Address</source>
+ <translation>Adresse</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Merkelapp</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Melding</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Dato</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Merkelapp</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Melding</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(ingen merkelapp)</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -1452,7 +1804,31 @@
<source>S&amp;end</source>
<translation>S&amp;end</translation>
</message>
- </context>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Kopier mengde</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopier beløp</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Kopier gebyr</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Kopier veksel</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>eller</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(ingen merkelapp)</translation>
+ </message>
+</context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -1534,10 +1910,18 @@
</context>
<context>
<name>SendConfirmationDialog</name>
- </context>
+ <message>
+ <source>Yes</source>
+ <translation>Ja</translation>
+ </message>
+</context>
<context>
<name>ShutdownWindow</name>
<message>
+ <source>%1 is shutting down...</source>
+ <translation>%1 lukker...</translation>
+ </message>
+ <message>
<source>Do not shut down the computer until this window disappears.</source>
<translation>Slå ikke av datamaskinen før dette vinduet forsvinner.</translation>
</message>
@@ -1628,6 +2012,14 @@
<source>Reset all verify message fields</source>
<translation>Tilbakestill alle felter for meldingsverifikasjon</translation>
</message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation>Signering av melding feilet.</translation>
+ </message>
+ <message>
+ <source>Message signed.</source>
+ <translation>Melding signert.</translation>
+ </message>
</context>
<context>
<name>SplashScreen</name>
@@ -1645,6 +2037,38 @@
</context>
<context>
<name>TransactionDesc</name>
+ <message>
+ <source>Date</source>
+ <translation>Dato</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>Fra</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>ukjent</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation>Til</translation>
+ </message>
+ <message>
+ <source>not accepted</source>
+ <translation>ikke akseptert</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Melding</translation>
+ </message>
+ <message>
+ <source>Comment</source>
+ <translation>Kommentar</translation>
+ </message>
+ <message>
+ <source>Transaction ID</source>
+ <translation>Transaksjons-ID</translation>
+ </message>
</context>
<context>
<name>TransactionDescDialog</name>
@@ -1655,9 +2079,97 @@
</context>
<context>
<name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Dato</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Merkelapp</translation>
+ </message>
+ <message>
+ <source>Offline</source>
+ <translation>Frakoblet</translation>
+ </message>
+ <message>
+ <source>Unconfirmed</source>
+ <translation>Ubekreftet</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Sendt til</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(ingen merkelapp)</translation>
+ </message>
</context>
<context>
<name>TransactionView</name>
+ <message>
+ <source>All</source>
+ <translation>Alt</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>I dag</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>Denne uka</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>Denne måneden</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>Forrige måned</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>Dette året</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Sendt til</translation>
+ </message>
+ <message>
+ <source>To yourself</source>
+ <translation>Til deg selv</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Kopier adresse</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopier beløp</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Kopier transaksjons-ID</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Kommaseparert fil (*.csv)</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Dato</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Merkelapp</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adresse</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Eksportering feilet</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
@@ -1710,10 +2222,6 @@
<translation>Beskjæring: siste lommeboksynkronisering går utenfor beskjærte data. Du må bruke -reindex (laster ned hele blokkjeden igjen for beskjærte noder)</translation>
</message>
<message>
- <source>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, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Reduser lagringsbehovet ved beskjæring (sletting) av gamle blokker. Denne modusen er ikke kompatibel med -txindex og -rescan. Advarsel: Tilbakestilling av denne innstillingen krever at hele blokkjeden må lastes ned på nytt. (Standardverdi: 0 = deaktiver beskjæring av blokker, &gt;%u = mål for størrelse i MiB å bruke for blokkfiler)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Omsøk er ikke mulig i beskjært modus. Du vil måtte bruke -reindex som vil laste nede hele blokkjeden på nytt.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ne.ts b/src/qt/locale/bitcoin_ne.ts
index f7fb0e5a6e..be6e8e0391 100644
--- a/src/qt/locale/bitcoin_ne.ts
+++ b/src/qt/locale/bitcoin_ne.ts
@@ -41,6 +41,23 @@
<source>&amp;Delete</source>
<translation>&amp;amp;मेटाउनुहोस्</translation>
</message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>छनौट गर्नुहोस्...</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>पठाउने ठेगानाहरू...</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>प्राप्त गर्ने ठेगानाहरू...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>ठेगाना कपी गर्नुहोस्
+</translation>
+ </message>
</context>
<context>
<name>AddressTableModel</name>
@@ -192,6 +209,11 @@
<source>Amount</source>
<translation>रकम</translation>
</message>
+ <message>
+ <source>Copy address</source>
+ <translation>ठेगाना कपी गर्नुहोस्
+</translation>
+ </message>
</context>
<context>
<name>EditAddressDialog</name>
@@ -204,6 +226,10 @@
</context>
<context>
<name>Intro</name>
+ <message>
+ <source>%1 will download and store a copy of the Bitcoin block chain. At least %2GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory.</source>
+ <translation>%1 ले बिटकोइन ब्लक चेनको एउटा प्रतिलिपि डाउनलोड र भण्डारण गर्नेछ । यो निर्देशिकामा कम्तिमा पनि %2GB डाटा भण्डारण गरिनेछ, र यो समयसँगै बढ्नेछ । वालेटलाई पनि यो निर्देशिकामा भण्डारण गरिनेछ ।</translation>
+ </message>
</context>
<context>
<name>ModalOverlay</name>
@@ -213,6 +239,10 @@
</context>
<context>
<name>OptionsDialog</name>
+ <message>
+ <source>Choose the default subdivision unit to show in the interface and when sending coins.</source>
+ <translation>इन्टरफेसमा र सिक्का पठाउँदा देखिने डिफल्ट उपविभाजन एकाइ चयन गर्नुहोस् ।</translation>
+ </message>
</context>
<context>
<name>OverviewPage</name>
@@ -281,6 +311,10 @@
<source>Amount</source>
<translation>रकम</translation>
</message>
+ <message>
+ <source>Enter a Bitcoin address (e.g. %1)</source>
+ <translation>कृपया बिटकोइन ठेगाना प्रवेश गर्नुहोस् (उदाहरण %1)</translation>
+ </message>
</context>
<context>
<name>QObject::QObject</name>
@@ -310,14 +344,26 @@
</context>
<context>
<name>SendCoinsDialog</name>
+ <message>
+ <source>Choose...</source>
+ <translation>छनौट गर्नुहोस्...</translation>
+ </message>
</context>
<context>
<name>SendCoinsEntry</name>
<message>
+ <source>Choose previously used address</source>
+ <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>Enter a label for this address to add it to the list of used addresses</source>
+ <translation>यो ठेगानालाई प्रयोग गरिएको ठेगानाको सूचीमा थप्न एउटा लेबल प्रविष्ट गर्नुहोस्</translation>
+ </message>
+ <message>
<source>A message that was attached to the bitcoin: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Bitcoin network.</source>
<translation>बिटकोइनमा संलग्न गरिएको सन्देश: तपाईंको मध्यस्थको लागि कारोबारको साथमा भण्डारण गरिने URI । नोट: यो सन्देश बिटकोइन नेटवर्क मार्फत पठाइने छैन ।</translation>
</message>
@@ -334,6 +380,18 @@
<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>Choose previously used address</source>
+ <translation>पहिला प्रयोग गरिएको ठेगाना प्रयोग गर्नुहोस्</translation>
+ </message>
+ <message>
+ <source>Copy the current signature to the system clipboard</source>
+ <translation>वर्तमान हस्ताक्षरलाई प्रणाली क्लिपबोर्डमा कपी गर्नुहोस्</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>सन्देश प्रमाणित गर्न, तल दिइएको स्थानमा प्राप्तकर्ता ठेगाना, सन्देश (लाइन ब्रेक, स्पेस, ट्याब, आदि उस्तै गरी कपी गर्ने कुरा सुनिश्चित गर्नुहोस्) र हस्ताक्षर &amp;apos;s प्रविष्ट गर्नुहोस् । बीचमा-मानिसको-आक्रमणबाट बच्न हस्ताक्षर पढ्दा हस्ताक्षर गरिएको सन्देशमा जे छ त्यो भन्दा धेरै कुरामा ध्यान नदिनुहोस् । यो कार्यले हस्ताक्षर गर्ने पक्षले मात्र यो ठेगानाले प्राप्त गर्छ भन्ने कुरा प्रमाणित गर्छ, यसले कुनै पनि कारोबारको प्रेषककर्तालाई प्रमाणित गर्न सक्दैन भन्ने कुरा याद गर्नुहोस्!</translation>
+ </message>
</context>
<context>
<name>SplashScreen</name>
@@ -352,6 +410,11 @@
</context>
<context>
<name>TransactionView</name>
+ <message>
+ <source>Copy address</source>
+ <translation>ठेगाना कपी गर्नुहोस्
+</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
@@ -364,10 +427,23 @@
</context>
<context>
<name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;amp;निर्यात गर्नुहोस्
+</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>वर्तमान ट्याबको डाटालाई फाइलमा निर्यात गर्नुहोस्</translation>
+ </message>
</context>
<context>
<name>bitcoin-core</name>
<message>
+ <source>Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup</source>
+ <translation>वालेटको सबै कारोबार मेटाउनुहोस् र -स्टार्टअपको पुनः स्क्यान मार्फत ब्लकचेनका ती भागहरूलाई मात्र पुनः प्राप्त गर्नुहोस्</translation>
+ </message>
+ <message>
<source>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</source>
<translation>ब्लक डाटाबेसमा भविष्यबाट आए जस्तो देखिने एउटा ब्लक हुन्छ । तपाईंको कम्प्युटरको मिति र समय गलत तरिकाले सेट गरिएकाले यस्तो हुन सक्छ । तपाईं आफ्नो कम्प्युटरको मिति र समय सही छ भनेर पक्का हुनुहुन्छ भने मात्र ब्लक डाटाबेस पुनर्निर्माण गर्नुहोस् ।</translation>
</message>
diff --git a/src/qt/locale/bitcoin_nl.ts b/src/qt/locale/bitcoin_nl.ts
index 8a09bed2ce..e523e83281 100644
--- a/src/qt/locale/bitcoin_nl.ts
+++ b/src/qt/locale/bitcoin_nl.ts
@@ -3,7 +3,7 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation>Klik met de rechtermuisknop om het adres of label te wijzigen</translation>
+ <translation>Rechtermuisklik om het adres of label te wijzigen</translation>
</message>
<message>
<source>Create a new address</source>
@@ -318,6 +318,22 @@
<translation>Open &amp;URI...</translation>
</message>
<message>
+ <source>Click to disable network activity.</source>
+ <translation>Klik om de netwerkactiviteit te stoppen.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>Netwerkactiviteit gestopt.</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>Klik om de netwerkactiviteit opnieuw te starten.</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>Kopteksten synchroniseren (%1%)...</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>Bezig met herindexeren van blokken op harde schijf...</translation>
</message>
@@ -429,10 +445,6 @@
<source>Processing blocks on disk...</source>
<translation>Bezig met verwerken van blokken op harde schijf...</translation>
</message>
- <message>
- <source>No block source available...</source>
- <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 transactiegeschiedenis verwerkt.</numerusform><numerusform>%n blokken aan transactiegeschiedenis verwerkt.</numerusform></translation>
@@ -474,6 +486,10 @@
<translation>%1 client</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>Gelijke worden verbonden...</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>Aan het bijwerken...</translation>
</message>
@@ -516,6 +532,14 @@
<translation>Binnenkomende transactie</translation>
</message>
<message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation>HD sleutel voortbrenging is &lt;b&gt;ingeschakeld&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation>HD sleutel voortbrenging is &lt;b&gt;uitgeschakeld&lt;/b&gt;</translation>
+ </message>
+ <message>
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
<translation>Portemonnee is &lt;b&gt;versleuteld&lt;/b&gt; en momenteel &lt;b&gt;geopend&lt;/b&gt;</translation>
</message>
@@ -523,7 +547,11 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Portemonnee is &lt;b&gt;versleuteld&lt;/b&gt; en momenteel &lt;b&gt;gesloten&lt;/b&gt;</translation>
</message>
- </context>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>Een fatale fout heeft zich voorgedaan. Bitcoin kan niet veilig worden verdergezet en wordt afgesloten.</translation>
+ </message>
+</context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -858,14 +886,50 @@
<translation>Vorm</translation>
</message>
<message>
+ <source>Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source>
+ <translation>Recente transacties zijn mogelijk nog niet zichtbaar. De balans van de geldbeugel is daarom mogelijk niet correct. Deze informatie is correct van zodra de synchronisatie met het Bitcoin-netwerk werd voltooid, zoals onderaan beschreven.</translation>
+ </message>
+ <message>
+ <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source>
+ <translation>Poging om bitcoins te besteden die door "nog niet weergegeven" transacties worden beïnvloed, worden niet door het netwerk geaccepteerd.</translation>
+ </message>
+ <message>
+ <source>Number of blocks left</source>
+ <translation>Aantal blokken resterend.</translation>
+ </message>
+ <message>
+ <source>Unknown...</source>
+ <translation>Onbekend...</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation>Tijd laatste blok</translation>
</message>
<message>
+ <source>Progress</source>
+ <translation>Vooruitgang</translation>
+ </message>
+ <message>
+ <source>Progress increase per hour</source>
+ <translation>Vooruitgang per uur</translation>
+ </message>
+ <message>
+ <source>calculating...</source>
+ <translation>Berekenen...</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation>Geschatte tijd tot volledig synchroon</translation>
+ </message>
+ <message>
<source>Hide</source>
<translation>Verbergen</translation>
</message>
- </context>
+ <message>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation>Onbekend. Kopteksten synchroniseren (%1%)...</translation>
+ </message>
+</context>
<context>
<name>OpenURIDialog</name>
<message>
@@ -1300,7 +1364,15 @@
<source>Node/Service</source>
<translation>Node/Dienst</translation>
</message>
- </context>
+ <message>
+ <source>NodeId</source>
+ <translation>Node ID</translation>
+ </message>
+ <message>
+ <source>Ping</source>
+ <translation>Ping</translation>
+ </message>
+</context>
<context>
<name>QObject</name>
<message>
@@ -1339,14 +1411,54 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation><numerusform>%n seconde</numerusform><numerusform>%n seconden</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation><numerusform>%n minuut</numerusform><numerusform>%n minuten</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation><numerusform>%n uur</numerusform><numerusform>%n uren</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation><numerusform>%n dag</numerusform><numerusform>%n dagen</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation><numerusform>%n week</numerusform><numerusform>%n weken</numerusform></translation>
+ </message>
<message>
<source>%1 and %2</source>
<translation>%1 en %2</translation>
</message>
- </context>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation><numerusform>%n jaar</numerusform><numerusform>%n jaren</numerusform></translation>
+ </message>
+ <message>
+ <source>%1 didn't yet exit safely...</source>
+ <translation>%1 sloot nog niet veilig af...</translation>
+ </message>
+</context>
<context>
<name>QObject::QObject</name>
- </context>
+ <message>
+ <source>Error: Specified data directory "%1" does not exist.</source>
+ <translation>Fout: Opgegeven gegevensmap "%1" bestaat niet.</translation>
+ </message>
+ <message>
+ <source>Error: Cannot parse configuration file: %1. Only use key=value syntax.</source>
+ <translation>Fout: Kan configuratiebestand niet verwerken: %1. Gebruik enkel de key=value syntax.</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation>Fout: %1</translation>
+ </message>
+</context>
<context>
<name>QRImageWidget</name>
<message>
@@ -1525,6 +1637,10 @@
<translation>Pingwachttijd</translation>
</message>
<message>
+ <source>Min Ping</source>
+ <translation>Min Ping</translation>
+ </message>
+ <message>
<source>Time Offset</source>
<translation>Tijdcompensatie</translation>
</message>
@@ -1585,6 +1701,18 @@
<translation>1 &amp;jaar</translation>
</message>
<message>
+ <source>&amp;Disconnect</source>
+ <translation>&amp;Verbreek verbinding</translation>
+ </message>
+ <message>
+ <source>Ban for</source>
+ <translation>Ban Node voor</translation>
+ </message>
+ <message>
+ <source>&amp;Unban</source>
+ <translation>&amp;Maak ban voor Node ongedaan</translation>
+ </message>
+ <message>
<source>Welcome to the %1 RPC console.</source>
<translation>Welkom bij de %1 RPC-console.</translation>
</message>
@@ -1597,6 +1725,14 @@
<translation>Typ &lt;b&gt;help&lt;/b&gt; voor een overzicht van de beschikbare opdrachten.</translation>
</message>
<message>
+ <source>WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramification of a command.</source>
+ <translation>WAARSCHUWING: Er zijn Scammers actief geweest, die gebruikers vragen om hier commando's te typen, waardoor de inhoud van hun portefeuille werd gestolen. Gebruik deze console niet zonder de toedracht van een opdracht volledig te begrijpen.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled</source>
+ <translation>Netwerkactiviteit uitgeschakeld</translation>
+ </message>
+ <message>
<source>%1 B</source>
<translation>%1 B</translation>
</message>
@@ -1716,6 +1852,10 @@
<translation>Verwijder</translation>
</message>
<message>
+ <source>Copy URI</source>
+ <translation>Kopieer URI</translation>
+ </message>
+ <message>
<source>Copy label</source>
<translation>Kopieer label</translation>
</message>
@@ -1941,6 +2081,10 @@
<translation>Stof:</translation>
</message>
<message>
+ <source>Confirmation time target:</source>
+ <translation>Bevestigingstijddoel:</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>Verwijder &amp;Alles</translation>
</message>
@@ -2033,6 +2177,10 @@
<translation>Transactiecreatie mislukt</translation>
</message>
<message>
+ <source>The transaction was rejected with the following reason: %1</source>
+ <translation>De transactie werd afgewezen om de volgende reden: %1</translation>
+ </message>
+ <message>
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation>Een vergoeding van meer dan %1 wordt beschouwd als een absurd hoge vergoeding.</translation>
</message>
@@ -2040,10 +2188,18 @@
<source>Payment request expired.</source>
<translation>Betalingsverzoek verlopen.</translation>
</message>
+ <message numerus="yes">
+ <source>%n block(s)</source>
+ <translation><numerusform>%n blok</numerusform><numerusform>%n blokken</numerusform></translation>
+ </message>
<message>
<source>Pay only the required fee of %1</source>
<translation>Betaal alleen de verplichte transactiekosten van %1</translation>
</message>
+ <message numerus="yes">
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation><numerusform>Schatting is dat bevestiging begint over %n blok.</numerusform><numerusform>Schatting is dat bevestiging begint over %n blokken.</numerusform></translation>
+ </message>
<message>
<source>Warning: Invalid Bitcoin address</source>
<translation>Waarschuwing: Ongeldig Bitcoinadres</translation>
@@ -2053,6 +2209,14 @@
<translation>Waarschuwing: Onbekend wisselgeldadres</translation>
</message>
<message>
+ <source>Confirm custom change address</source>
+ <translation>Bevestig aangepast wisselgeldadres</translation>
+ </message>
+ <message>
+ <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source>
+ <translation>Het wisselgeldadres dat u heeft geselecteerd maakt geen deel uit van deze portemonnee. Een deel of zelfs alle geld in uw portemonnee kan mogelijk naar dit adres worden verzonden. Weet je het zeker?</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(geen label)</translation>
</message>
@@ -2313,6 +2477,10 @@
</context>
<context>
<name>TransactionDesc</name>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>Open voor nog %n blok</numerusform><numerusform>Open voor nog %n blokken</numerusform></translation>
+ </message>
<message>
<source>Open until %1</source>
<translation>Open tot %1</translation>
@@ -2397,6 +2565,10 @@
<source>Credit</source>
<translation>Credit</translation>
</message>
+ <message numerus="yes">
+ <source>matures in %n more block(s)</source>
+ <translation><numerusform>komt beschikbaar na %n nieuwe blok</numerusform><numerusform>komt beschikbaar na %n nieuwe blokken</numerusform></translation>
+ </message>
<message>
<source>not accepted</source>
<translation>niet geaccepteerd</translation>
@@ -2434,6 +2606,10 @@
<translation>Transactie-ID</translation>
</message>
<message>
+ <source>Transaction total size</source>
+ <translation>Transactie totale grootte</translation>
+ </message>
+ <message>
<source>Output index</source>
<translation>Output index</translation>
</message>
@@ -2495,6 +2671,10 @@
<source>Label</source>
<translation>Label</translation>
</message>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>Open voor nog %n blok</numerusform><numerusform>Open voor nog %n blokken</numerusform></translation>
+ </message>
<message>
<source>Open until %1</source>
<translation>Open tot %1</translation>
@@ -2826,6 +3006,18 @@
<translation>Aanvaard opdrachtregel- en JSON-RPC-opdrachten</translation>
</message>
<message>
+ <source>Accept connections from outside (default: 1 if no -proxy or -connect/-noconnect)</source>
+ <translation>Accepteer verbindingen van buitenaf (standaard: 1 indien geen -proxy of -connect/-noconnect werd opgegeven)</translation>
+ </message>
+ <message>
+ <source>Connect only to the specified node(s); -noconnect or -connect=0 alone to disable automatic connections</source>
+ <translation>Verbind enkel met de opgegeven knooppunt(en); -noconnect of -connect = 0 alleen om automatische verbindingen uit te schakelen</translation>
+ </message>
+ <message>
+ <source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
+ <translation>Uitgegeven onder de MIT software licentie, zie het bijgevoegde bestand %s of %s</translation>
+ </message>
+ <message>
<source>If &lt;category&gt; is not supplied or if &lt;category&gt; = 1, output all debugging information.</source>
<translation>Als er geen &lt;categorie&gt; is opgegeven of als de &lt;categorie&gt; 1 is, laat dan alle debugginginformatie zien.</translation>
</message>
@@ -2838,10 +3030,6 @@
<translation>Snoei: laatste portemoneesynchronisatie gaat verder dan de gesnoeide data. U moet -reindex gebruiken (download opnieuw de gehele blokketen voor een weggesnoeide node)</translation>
</message>
<message>
- <source>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, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Beperk benodigde opslag door snoeien (verwijderen) van oude blokken. Deze modus is niet-compatibele met -txindex en -rescan. Waarschuwing: Terugzetten van deze instellingen vereist opnieuw downloaden van gehele de blokketen. (standaard:0 = uitzetten snoeimodus, &gt;%u = doelgrootte in MiB voor blokbestanden)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Herscannen is niet mogelijk in de snoeimodus. U moet -reindex gebruiken dat de hele blokketen opnieuw zal downloaden.</translation>
</message>
@@ -2906,6 +3094,14 @@
<translation>Voer opdracht uit zodra een portemonneetransactie verandert (%s in cmd wordt vervangen door TxID)</translation>
</message>
<message>
+ <source>Extra transactions to keep in memory for compact block reconstructions (default: %u)</source>
+ <translation>Extra transacties wordt bijgehouden voor compacte blokreconstructie (standaard: %u)</translation>
+ </message>
+ <message>
+ <source>If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)</source>
+ <translation>Als dit blok in de keten staat, gaat het ervan uit dat dit blok en zijn voorouders geldig zijn en mogelijk hun script verificatie overslaan (0 om alles te verifiëren, standaard:%s, testnet:%s)</translation>
+ </message>
+ <message>
<source>Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)</source>
<translation>Maximum toegestane peer tijd compensatie. Lokaal perspectief van tijd mag worden beinvloed door peers die met deze hoeveelheid voor of achter lopen. (standaard: %u seconden)</translation>
</message>
@@ -2922,6 +3118,14 @@
<translation>Gelieve bij te dragen als je %s nuttig vindt. Bezoek %s voor meer informatie over de software.</translation>
</message>
<message>
+ <source>Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, &gt;%u = automatically prune block files to stay under the specified target size in MiB)</source>
+ <translation>Beperk benodigde opslag door trimmen (verwijderen) van oude blokken in te schakelen. Dit maakt het mogelijk om de pruneblockchain RPC aan te roepen om specifieke blokken te verwijderen, en maakt het automatische trimmen van oude blokken mogelijk wanneer een doelgrootte in MiB is voorzien. Deze modus is niet compatibele met -txindex en -rescan. Waarschuwing: Terugzetten van deze instellingen vereist het opnieuw downloaden van gehele de blokketen. (standaard:0 = uitzetten trimmodus, 1 = manueel trimmen via RPC toestaan, &gt;%u = automatisch blokbestanden trimmen om beneden de gespecificeerde doelgrootte in MiB te blijven)</translation>
+ </message>
+ <message>
+ <source>Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)</source>
+ <translation>Specificeer het laagste tarief (in %s/kB) voor transacties die bij het maken van een blok moeten worden in rekening worden gebracht (standaard: %s)</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>Kies het aantal scriptverificatie processen (%u tot %d, 0 = auto, &lt;0 = laat dit aantal kernen vrij, standaard: %d)</translation>
</message>
@@ -2930,6 +3134,10 @@
<translation>De blokdatabase bevat een blok dat lijkt uit de toekomst te komen. Dit kan gebeuren omdat de datum en tijd van uw computer niet goed staat. Herbouw de blokdatabase pas nadat u de datum en tijd van uw computer correct heeft ingesteld.</translation>
</message>
<message>
+ <source>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source>
+ <translation>Dit is een pre-release testversie - gebruik op eigen risico! Gebruik deze niet voor het delven van munten of handelsdoeleinden</translation>
+ </message>
+ <message>
<source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source>
<translation>Niet mogelijk om de databank terug te draaien naar een staat voor de vork. Je zal je blokketen opnieuw moeten downloaden</translation>
</message>
@@ -2938,6 +3146,22 @@
<translation>Gebruik UPnP om de luisterende poort te mappen (standaard: 1 als er geluisterd worden en geen -proxy is meegegeven)</translation>
</message>
<message>
+ <source>Username and hashed password for JSON-RPC connections. The field &lt;userpw&gt; comes in the format: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=&lt;USERNAME&gt;/rpcpassword=&lt;PASSWORD&gt; pair of arguments. This option can be specified multiple times</source>
+ <translation>Gebruikersnaam en gehasht wachtwoord voor JSON-RPC-verbindingen. De velden &lt;userpw&gt; is in het formaat: &lt;GEBRUIKERSNAAM&gt;:&lt;SALT&gt;$&lt;HASH&gt;. Een kanoniek Pythonscript is inbegrepen in de share/rpcuser. De klant connecteert dan normaal via de rpcuser=&lt;GEBRUIKERSNAAM&gt;/rpcpassword=&lt;PASWOORD&gt; argumenten. Deze optie kan meerdere keren worden meegegeven</translation>
+ </message>
+ <message>
+ <source>Wallet will not create transactions that violate mempool chain limits (default: %u)</source>
+ <translation>Portemonnee creëert geen transacties die mempool-ketenlimieten schenden (standaard: %u)</translation>
+ </message>
+ <message>
+ <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
+ <translation>Waarschuwing: Het lijkt erop dat het netwerk geen consensus kan vinden! Sommige delvers lijken problemen te ondervinden.</translation>
+ </message>
+ <message>
+ <source>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source>
+ <translation>Waarschuwing: Het lijkt erop dat we geen consensus kunnen vinden met onze peers! Mogelijk dient u te upgraden, of andere nodes moeten wellicht upgraden.</translation>
+ </message>
+ <message>
<source>You need to rebuild the database using -reindex-chainstate to change -txindex</source>
<translation>Om -txindex te kunnen veranderen dient u de database opnieuw te bouwen met gebruik van -reindex-chainstate.</translation>
</message>
@@ -2970,6 +3194,10 @@
<translation>Kan -%s adres niet herleiden: '%s'</translation>
</message>
<message>
+ <source>Chain selection options:</source>
+ <translation>Keten selectie opties:</translation>
+ </message>
+ <message>
<source>Change index out of range</source>
<translation>Wijzigingsindex buiten bereik</translation>
</message>
@@ -3166,6 +3394,10 @@
<translation>Gebruik UPnP om de luisterende poort te mappen (standaard: %u)</translation>
</message>
<message>
+ <source>Use the test chain</source>
+ <translation>Gebruik de test keten</translation>
+ </message>
+ <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation>User Agentcommentaar (%s) bevat onveilige karakters.</translation>
</message>
@@ -3458,10 +3690,22 @@
<translation>Output extra debugginginformatie (standaard: %u, het leveren van &lt;categorie&gt; is optioneel)</translation>
</message>
<message>
+ <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect/-noconnect)</source>
+ <translation>Query voor peer-adressen via DNS-lookup , indien laag aan adressen (default: 1 unless -connect/-noconnect)</translation>
+ </message>
+ <message>
<source>Support filtering of blocks and transaction with bloom filters (default: %u)</source>
<translation>Ondersteun filtering van blokken en transacties met bloomfilters (standaard: %u)</translation>
</message>
<message>
+ <source>This is the transaction fee you may pay when fee estimates are not available.</source>
+ <translation>Dit is de transactiekost die je mogelijk betaald indien geschatte tarief niet beschikbaar is</translation>
+ </message>
+ <message>
+ <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit %s and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
+ <translation>Dit product bevat software dat ontwikkeld is door het OpenSSL Project voor gebruik in de OpenSSL Toolkit %s en cryptografische software geschreven door Eric Young en UPnP software geschreven door Thomas Bernard.</translation>
+ </message>
+ <message>
<source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source>
<translation>Totale lengte van netwerkversiestring (%i) overschrijdt maximale lengte (%i). Verminder het aantal of grootte van uacomments.</translation>
</message>
@@ -3490,6 +3734,14 @@
<translation>Waarschuwing: portomonee bestand is corrupt, data is veiliggesteld! Originele %s is opgeslagen als %s in %s; als uw balans of transacties incorrect zijn dient u een backup terug te zetten.</translation>
</message>
<message>
+ <source>Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR notated network (e.g. 1.2.3.0/24). Can be specified multiple times.</source>
+ <translation>Goedgekeurde peers die verbinden vanaf een bepaald IP adres (vb. 1.2.3.4) of CIDR genoteerd netwerk (vb. 1.2.3.0/24). Kan meerdere keren worden gespecificeerd.</translation>
+ </message>
+ <message>
+ <source>%s is set very high!</source>
+ <translation>%s is zeer hoog ingesteld!</translation>
+ </message>
+ <message>
<source>(default: %s)</source>
<translation>(standaard: %s)</translation>
</message>
@@ -3510,6 +3762,10 @@
<translation>Ongeldig -proxy adres: '%s'</translation>
</message>
<message>
+ <source>Keypool ran out, please call keypoolrefill first</source>
+ <translation>Keypool op geraakt, roep alsjeblieft eerst keypoolrefill functie aan</translation>
+ </message>
+ <message>
<source>Listen for JSON-RPC connections on &lt;port&gt; (default: %u or testnet: %u)</source>
<translation>Luister naar JSON-RPC-verbindingen op &lt;poort&gt; (standaard: %u of testnet: %u)</translation>
</message>
@@ -3546,6 +3802,10 @@
<translation>Geef non-P2SH multisig door (standaard: %u)</translation>
</message>
<message>
+ <source>Send transactions with full-RBF opt-in enabled (default: %u)</source>
+ <translation>Verstuur transacties met full-RBF opt-in ingeschakeld (standaard: %u)</translation>
+ </message>
+ <message>
<source>Set key pool size to &lt;n&gt; (default: %u)</source>
<translation>Stel sleutelpoelgrootte in op &lt;n&gt; (standaard: %u)</translation>
</message>
@@ -3578,10 +3838,34 @@
<translation>Netwerkthread starten...</translation>
</message>
<message>
+ <source>The wallet will avoid paying less than the minimum relay fee.</source>
+ <translation>De portemonnee vermijdt minder te betalen dan het minimale relay vergoeding.</translation>
+ </message>
+ <message>
+ <source>This is the minimum transaction fee you pay on every transaction.</source>
+ <translation>Dit is het minimum transactietarief dat je betaald op elke transactie.</translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you will pay if you send a transaction.</source>
+ <translation>Dit is het transactietarief dat je betaald wanneer je een transactie verstuurt.</translation>
+ </message>
+ <message>
<source>Threshold for disconnecting misbehaving peers (default: %u)</source>
<translation>Drempel om verbinding te verbreken naar zich misdragende peers (standaard: %u)</translation>
</message>
<message>
+ <source>Transaction amounts must not be negative</source>
+ <translation>Transactiebedragen moeten positief zijn</translation>
+ </message>
+ <message>
+ <source>Transaction has too long of a mempool chain</source>
+ <translation>Transactie heeft een te lange mempoolketen</translation>
+ </message>
+ <message>
+ <source>Transaction must have at least one recipient</source>
+ <translation>Transactie moet ten minste één ontvanger hebben</translation>
+ </message>
+ <message>
<source>Unknown network specified in -onlynet: '%s'</source>
<translation>Onbekend netwerk gespecificeerd in -onlynet: '%s'</translation>
</message>
diff --git a/src/qt/locale/bitcoin_pl.ts b/src/qt/locale/bitcoin_pl.ts
index b7369c5093..3675bd060a 100644
--- a/src/qt/locale/bitcoin_pl.ts
+++ b/src/qt/locale/bitcoin_pl.ts
@@ -168,14 +168,34 @@
<translation>Potwierdź szyfrowanie portfela</translation>
</message>
<message>
+ <source>Warning: If you encrypt your wallet and lose your passphrase, you will &lt;b&gt;LOSE ALL OF YOUR BITCOINS&lt;/b&gt;!</source>
+ <translation>Uwaga: jeśli zaszyfrujesz swój portfel i zgubisz hasło &lt;b&gt;STRACISZ WSZYSTKIE SWOJE BITCOINY&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Jesteś pewien, że chcesz zaszyfrować swój portfel?</translation>
+ </message>
+ <message>
<source>Wallet encrypted</source>
<translation>Portfel zaszyfrowany</translation>
</message>
<message>
+ <source>%1 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>%1 zamknie się aby dokończyć proces szyfrowania. Pamiętaj, że szyfrowanie portfela nie zabezpiecza w pełni Twoich bitcoinów przed kradzieżą przez wirusy lub trojany mogące zainfekować Twój komputer.</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>WAŻNE: Wszystkie wykonane wcześniej kopie pliku portfela powinny być zamienione na nowe, szyfrowane pliki. Z powodów bezpieczeństwa, poprzednie kopie nieszyfrowanych plików portfela staną się bezużyteczne jak tylko zaczniesz korzystać z nowego, szyfrowanego portfela.</translation>
+ </message>
+ <message>
<source>Wallet encryption failed</source>
<translation>Szyfrowanie portfela nie powiodło się</translation>
</message>
<message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Szyfrowanie portfela nie powiodło się z powodu wewnętrznego błędu. Twój portfel nie został zaszyfrowany.</translation>
+ </message>
+ <message>
<source>The supplied passphrases do not match.</source>
<translation>Podane hasła nie są takie same.</translation>
</message>
@@ -298,6 +318,22 @@
<translation>Otwórz URI...</translation>
</message>
<message>
+ <source>Click to disable network activity.</source>
+ <translation>Kliknij aby wyłączyć aktywność sieciową.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>Aktywność sieciowa została wyłączona.</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>Kliknij, aby ponownie włączyć aktywności sieciową.</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>Synchronizowanie headerów (%1%)...</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>Ponowne indeksowanie bloków na dysku...</translation>
</message>
@@ -399,7 +435,7 @@
</message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network</source>
- <translation><numerusform>%n aktywnych połączeń do sieci Bitcoin</numerusform><numerusform>%n aktywnych połączeń do sieci Bitcoin</numerusform><numerusform>%n aktywnych połączeń do sieci Bitcoin</numerusform></translation>
+ <translation><numerusform>%n aktywnych połączeń do sieci Bitcoin</numerusform><numerusform>%n aktywnych połączeń do sieci Bitcoin</numerusform><numerusform>%n aktywnych połączeń do sieci Bitcoin</numerusform><numerusform>%n aktywnych połączeń do sieci Bitcoin</numerusform></translation>
</message>
<message>
<source>Indexing blocks on disk...</source>
@@ -409,13 +445,9 @@
<source>Processing blocks on disk...</source>
<translation>Przetwarzanie blocks on disk...</translation>
</message>
- <message>
- <source>No block source available...</source>
- <translation>Brak dostępnych źródeł bloków...</translation>
- </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
- <translation><numerusform>Przetworzono %n bloków historii transakcji.</numerusform><numerusform>Przetworzono %n bloków historii transakcji.</numerusform><numerusform>Przetworzono %n bloków historii transakcji.</numerusform></translation>
+ <translation><numerusform>Przetworzono %n bloków historii transakcji.</numerusform><numerusform>Przetworzono %n bloków historii transakcji.</numerusform><numerusform>Przetworzono %n bloków historii transakcji.</numerusform><numerusform>Przetworzono %n bloków historii transakcji.</numerusform></translation>
</message>
<message>
<source>%1 behind</source>
@@ -454,6 +486,10 @@
<translation>%1 klient</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>Łączenie z peerami...</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>Trwa synchronizacja…</translation>
</message>
@@ -496,6 +532,14 @@
<translation>Transakcja przychodząca</translation>
</message>
<message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation>Generowanie kluczy HD jest &lt;b&gt;włączone&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation>Generowanie kluczy HD jest &lt;b&gt;wyłączone&lt;/b&gt;</translation>
+ </message>
+ <message>
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
<translation>Portfel jest &lt;b&gt;zaszyfrowany&lt;/b&gt; i obecnie &lt;b&gt;odblokowany&lt;/b&gt;</translation>
</message>
@@ -503,7 +547,11 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Portfel jest &lt;b&gt;zaszyfrowany&lt;/b&gt; i obecnie &lt;b&gt;zablokowany&lt;/b&gt;</translation>
</message>
- </context>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>Wystąpił krytyczny błąd. Bitcoin nie jest w stanie kontynuować bezpiecznie i zostanie zamknięty.</translation>
+ </message>
+</context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -694,6 +742,14 @@
<translation>Zmień adres wysyłania</translation>
</message>
<message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>Wprowadzony adres "%1" nie jest prawidłowym adresem Bitcoin.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book.</source>
+ <translation>Wprowadzony adres "%1" znajduje się już w książce adresowej.</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation>Nie można było odblokować portfela.</translation>
</message>
@@ -816,11 +872,11 @@
</message>
<message numerus="yes">
<source>%n GB of free space available</source>
- <translation><numerusform>%n GB dostępnego wolnego miejsca</numerusform><numerusform>%n GB dostępnego wolnego miejsca</numerusform><numerusform>%n GB dostępnego wolnego miejsca</numerusform></translation>
+ <translation><numerusform>%n GB dostępnego wolnego miejsca</numerusform><numerusform>%n GB dostępnego wolnego miejsca</numerusform><numerusform>%n GB dostępnego wolnego miejsca</numerusform><numerusform>%n GB dostępnego wolnego miejsca</numerusform></translation>
</message>
<message numerus="yes">
<source>(of %n GB needed)</source>
- <translation><numerusform>(z %n GB potrzebnych)</numerusform><numerusform>(z %n GB potrzebnych)</numerusform><numerusform>(z %n GB potrzebnych)</numerusform></translation>
+ <translation><numerusform>(z %n GB potrzebnych)</numerusform><numerusform>(z %n GB potrzebnych)</numerusform><numerusform>(z %n GB potrzebnych)</numerusform><numerusform>(z %n GB potrzebnych)</numerusform></translation>
</message>
</context>
<context>
@@ -830,6 +886,10 @@
<translation>Formularz</translation>
</message>
<message>
+ <source>Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source>
+ <translation>Świeże transakcje mogą nie być jeszcze widoczne, a zatem saldo portfela może być nieprawidłowe. Te detale będą poprawne, gdy portfel zakończy synchronizację z siecią bitcoin, zgodnie z poniższym opisem.</translation>
+ </message>
+ <message>
<source>Number of blocks left</source>
<translation>Pozostało bloków</translation>
</message>
@@ -1209,7 +1269,59 @@
<source>Cannot start bitcoin: click-to-pay handler</source>
<translation>Nie można uruchomić protokołu bitcoin: kliknij-by-zapłacić</translation>
</message>
- </context>
+ <message>
+ <source>URI handling</source>
+ <translation>Obsługa URI</translation>
+ </message>
+ <message>
+ <source>Invalid payment address %1</source>
+ <translation>błędny adres płatności %1</translation>
+ </message>
+ <message>
+ <source>Payment request rejected</source>
+ <translation>Żądanie płatności odrzucone</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Żądanie płatności upłynęło.</translation>
+ </message>
+ <message>
+ <source>Payment request is not initialized.</source>
+ <translation>Żądanie płatności nie jest zainicjowane.</translation>
+ </message>
+ <message>
+ <source>Unverified payment requests to custom payment scripts are unsupported.</source>
+ <translation>Niezweryfikowane żądania płatności do własnych skryptów płatności są niewspierane.</translation>
+ </message>
+ <message>
+ <source>Invalid payment request.</source>
+ <translation>Nieprawidłowe żądanie płatności</translation>
+ </message>
+ <message>
+ <source>Refund from %1</source>
+ <translation>Zwrot z %1</translation>
+ </message>
+ <message>
+ <source>Error communicating with %1: %2</source>
+ <translation>Błąd komunikacji z %1 : %2</translation>
+ </message>
+ <message>
+ <source>Payment request cannot be parsed!</source>
+ <translation>Żądanie płatności nie może zostać przetworzone.</translation>
+ </message>
+ <message>
+ <source>Bad response from server %1</source>
+ <translation>Błędna odpowiedź z serwera %1</translation>
+ </message>
+ <message>
+ <source>Network request error</source>
+ <translation>Błąd żądania sieci</translation>
+ </message>
+ <message>
+ <source>Payment acknowledged</source>
+ <translation>Płatność potwierdzona</translation>
+ </message>
+</context>
<context>
<name>PeerTableModel</name>
<message>
@@ -1220,7 +1332,15 @@
<source>Node/Service</source>
<translation>Węzeł/Usługi</translation>
</message>
- </context>
+ <message>
+ <source>NodeId</source>
+ <translation>Identyfikator węzła</translation>
+ </message>
+ <message>
+ <source>Ping</source>
+ <translation>Ping</translation>
+ </message>
+</context>
<context>
<name>QObject</name>
<message>
@@ -1259,17 +1379,69 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation><numerusform>%n sekunda</numerusform><numerusform>%n sekund</numerusform><numerusform>%n sekund</numerusform><numerusform>%n sekund</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation><numerusform>%n minuta</numerusform><numerusform>%n minut</numerusform><numerusform>%n minut</numerusform><numerusform>%n minut</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation><numerusform>%n godzinę</numerusform><numerusform>%n godziny</numerusform><numerusform>%n godzin</numerusform><numerusform>%n godzin</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation><numerusform>%n dzień</numerusform><numerusform>%n dni</numerusform><numerusform>%n dni</numerusform><numerusform>%n dni</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation><numerusform>%n tydzień</numerusform><numerusform>%n tygodnie</numerusform><numerusform>%n tygodni</numerusform><numerusform>%n tygodni</numerusform></translation>
+ </message>
<message>
<source>%1 and %2</source>
<translation>%1 i %2</translation>
</message>
- </context>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation><numerusform>%n rok</numerusform><numerusform>%n lata</numerusform><numerusform>%n lat</numerusform><numerusform>%n lat</numerusform></translation>
+ </message>
+ <message>
+ <source>%1 didn't yet exit safely...</source>
+ <translation>%1 jeszcze się bezpiecznie nie zamknął...</translation>
+ </message>
+</context>
<context>
<name>QObject::QObject</name>
- </context>
+ <message>
+ <source>Error: Specified data directory "%1" does not exist.</source>
+ <translation>Błąd: Określony folder danych "%1" nie istnieje.</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation>Błąd: %1</translation>
+ </message>
+</context>
<context>
<name>QRImageWidget</name>
- </context>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;Zapisz obraz...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>&amp;Kopiuj obraz</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>Zapisz Kod QR</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>Obraz PNG (*.png)</translation>
+ </message>
+</context>
<context>
<name>RPCConsole</name>
<message>
@@ -1429,6 +1601,10 @@
<translation>Czas odpowiedzi</translation>
</message>
<message>
+ <source>Min Ping</source>
+ <translation>Minimalny czas odpowiedzi</translation>
+ </message>
+ <message>
<source>Time Offset</source>
<translation>Przesunięcie czasu</translation>
</message>
@@ -1489,6 +1665,18 @@
<translation>1 &amp;rok</translation>
</message>
<message>
+ <source>&amp;Disconnect</source>
+ <translation>&amp;Rozłącz</translation>
+ </message>
+ <message>
+ <source>Ban for</source>
+ <translation>Zbanuj na</translation>
+ </message>
+ <message>
+ <source>&amp;Unban</source>
+ <translation>&amp;Odblokuj</translation>
+ </message>
+ <message>
<source>Welcome to the %1 RPC console.</source>
<translation>Witaj w konsoli %1 RPC.</translation>
</message>
@@ -1620,10 +1808,18 @@
<translation>Usuń</translation>
</message>
<message>
+ <source>Copy URI</source>
+ <translation>Kopiuj URI:</translation>
+ </message>
+ <message>
<source>Copy label</source>
<translation>Kopiuj etykietę</translation>
</message>
<message>
+ <source>Copy message</source>
+ <translation>Kopiuj wiadomość</translation>
+ </message>
+ <message>
<source>Copy amount</source>
<translation>Kopiuj kwotę</translation>
</message>
@@ -1647,13 +1843,33 @@
<translation>&amp;Zapisz obraz...</translation>
</message>
<message>
+ <source>Request payment to %1</source>
+ <translation>Zażądaj płatności do %1</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>Informacje o płatności</translation>
+ </message>
+ <message>
+ <source>URI</source>
+ <translation>URI</translation>
+ </message>
+ <message>
<source>Address</source>
<translation>Adres</translation>
</message>
<message>
+ <source>Amount</source>
+ <translation>Kwota</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>Etykieta</translation>
</message>
+ <message>
+ <source>Message</source>
+ <translation>Wiadomość</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
@@ -1666,10 +1882,26 @@
<translation>Etykieta</translation>
</message>
<message>
+ <source>Message</source>
+ <translation>Wiadomość</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(brak etykiety)</translation>
</message>
- </context>
+ <message>
+ <source>(no message)</source>
+ <translation>(brak wiadomości)</translation>
+ </message>
+ <message>
+ <source>(no amount requested)</source>
+ <translation>(brak kwoty)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation>Zażądano</translation>
+ </message>
+</context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1797,6 +2029,10 @@
<translation>Pył:</translation>
</message>
<message>
+ <source>Confirmation time target:</source>
+ <translation>Docelowy czas potwierdzenia:</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>Wyczyść &amp;wszystko</translation>
</message>
@@ -1841,6 +2077,66 @@
<translation>Skopiuj resztę</translation>
</message>
<message>
+ <source>%1 to %2</source>
+ <translation>%1 do %2</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to send?</source>
+ <translation>Czy na pewno chcesz wysłać?</translation>
+ </message>
+ <message>
+ <source>added as transaction fee</source>
+ <translation>dodano jako opłata transakcyjna</translation>
+ </message>
+ <message>
+ <source>Total Amount %1</source>
+ <translation>Łączna kwota %1</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>lub</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation>Potwierdź wysyłanie monet</translation>
+ </message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>Adres odbiorcy jest nieprawidłowy, proszę sprawić ponownie.</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation>Kwota do zapłacenia musi być większa od 0.</translation>
+ </message>
+ <message>
+ <source>The amount exceeds your balance.</source>
+ <translation>Kwota przekracza twoje saldo.</translation>
+ </message>
+ <message>
+ <source>The total exceeds your balance when the %1 transaction fee is included.</source>
+ <translation>Suma przekracza twoje saldo, gdy doliczymy %1 opłaty transakcyjnej.</translation>
+ </message>
+ <message>
+ <source>Transaction creation failed!</source>
+ <translation>Utworzenie transakcji nie powiodło się!</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Żądanie płatności upłynęło.</translation>
+ </message>
+ <message>
+ <source>Pay only the required fee of %1</source>
+ <translation>Zapłać tylko wymaganą opłatę w wysokości %1</translation>
+ </message>
+ <message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>Ostrzeżenie: nieprawidłowy adres Bitcoin</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <translation>Ostrzeżenie: Nieznany adres reszty</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(brak etykiety)</translation>
</message>
@@ -1926,7 +2222,11 @@
</context>
<context>
<name>SendConfirmationDialog</name>
- </context>
+ <message>
+ <source>Yes</source>
+ <translation>Tak</translation>
+ </message>
+</context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -2025,7 +2325,35 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<source>Reset all verify message fields</source>
<translation>Resetuje wszystkie pola weryfikacji wiadomości</translation>
</message>
- </context>
+ <message>
+ <source>The entered address is invalid.</source>
+ <translation>Podany adres jest nieprawidłowy.</translation>
+ </message>
+ <message>
+ <source>Please check the address and try again.</source>
+ <translation>Proszę sprawdzić adres i spróbować ponownie.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock was cancelled.</source>
+ <translation>Odblokowanie portfela zostało anulowane.</translation>
+ </message>
+ <message>
+ <source>Private key for the entered address is not available.</source>
+ <translation>Klucz prywatny dla podanego adresu nie jest dostępny.</translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation>Podpisanie wiadomości nie powiodło się.</translation>
+ </message>
+ <message>
+ <source>Message signed.</source>
+ <translation>Wiadomość podpisana.</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation>Wiadomość zweryfikowana.</translation>
+ </message>
+</context>
<context>
<name>SplashScreen</name>
<message>
@@ -2043,6 +2371,10 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<context>
<name>TransactionDesc</name>
<message>
+ <source>abandoned</source>
+ <translation>porzucone</translation>
+ </message>
+ <message>
<source>Date</source>
<translation>Data</translation>
</message>
@@ -2078,7 +2410,35 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<source>label</source>
<translation>etykieta</translation>
</message>
- </context>
+ <message>
+ <source>Transaction fee</source>
+ <translation>Opłata transakcyjna</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Wiadomość</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation>Transakcja</translation>
+ </message>
+ <message>
+ <source>Inputs</source>
+ <translation>Wejścia</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Kwota</translation>
+ </message>
+ <message>
+ <source>true</source>
+ <translation>prawda</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation>fałsz</translation>
+ </message>
+</context>
<context>
<name>TransactionDescDialog</name>
<message>
@@ -2093,6 +2453,10 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation>Data</translation>
</message>
<message>
+ <source>Type</source>
+ <translation>Typ</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>Etykieta</translation>
</message>
@@ -2180,6 +2544,10 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation>Skopiuj ID transakcji</translation>
</message>
<message>
+ <source>Edit label</source>
+ <translation>Zmień etykietę</translation>
+ </message>
+ <message>
<source>Comma separated file (*.csv)</source>
<translation>Plik *.CSV (dane rozdzielane przecinkami)</translation>
</message>
@@ -2188,6 +2556,10 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation>Data</translation>
</message>
<message>
+ <source>Type</source>
+ <translation>Typ</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>Etykieta</translation>
</message>
@@ -2199,7 +2571,15 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<source>Exporting Failed</source>
<translation>Eksportowanie nie powiodło się</translation>
</message>
- </context>
+ <message>
+ <source>Range:</source>
+ <translation>Zakres:</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>do</translation>
+ </message>
+</context>
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
@@ -2215,7 +2595,23 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
</context>
<context>
<name>WalletView</name>
- </context>
+ <message>
+ <source>Backup Wallet</source>
+ <translation>Kopia zapasowa portfela</translation>
+ </message>
+ <message>
+ <source>Backup Failed</source>
+ <translation>Nie udało się wykonać kopii zapasowej</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation>Wykonano kopię zapasową</translation>
+ </message>
+ <message>
+ <source>The wallet data was successfully saved to %1.</source>
+ <translation>Dane portfela zostały poprawnie zapisane w %1.</translation>
+ </message>
+</context>
<context>
<name>bitcoin-core</name>
<message>
@@ -2251,10 +2647,6 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation>Prune: ostatnia synchronizacja portfela jest za danymi. Muszisz -reindexować (pobrać cały ciąg bloków ponownie w przypadku przyciętego węzła)</translation>
</message>
<message>
- <source>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, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Zredukuj wymaganą ilość miejsca na dysku poprzez usuwanie starych bloków. Ten tryb jest niekompatybilny z -txindex oraz -rescan. Ostrzeżenie: Wycofanie tego ustawienia wymaga ponownego pobrania całego łańcucha bloków. (domyślnie: 0 = wyłącz usuwanie bloków, &gt;%u = docelowy rozmiar w MiB jaki wykorzystać na pliki z blokami)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Ponowne skanowanie nie jest możliwe w trybie przycinania. Będzie trzeba użyć -reindex, co pobierze ponownie cały łańcuch bloków.</translation>
</message>
@@ -2583,6 +2975,10 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation>Uruchom polecenie przy otrzymaniu odpowiedniego powiadomienia lub gdy zobaczymy naprawdę długie rozgałęzienie (%s w poleceniu jest podstawiane za komunikat)</translation>
</message>
<message>
+ <source>Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)</source>
+ <translation>Opłaty (w %s/Kb) mniejsze niż ta, będą traktowane jako zerowe przy tworzeniu, przesyłaniu i zatwierdzaniu transakcji (domyślnie: %s)</translation>
+ </message>
+ <message>
<source>If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)</source>
<translation>Jeżeli nie ustawiono paytxfee, dołącz wystarczająca opłatę, aby transakcja mogła zostać zatwierdzona w ciągu średniej ilości n bloków (domyślnie: %u)</translation>
</message>
@@ -2603,6 +2999,10 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation>Zbyt niska kwota transakcji do wysłania po odjęciu opłaty</translation>
</message>
<message>
+ <source>Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start</source>
+ <translation>Użyj hierarchicznej deterministycznej metody generowania kluczy (HD) zgodnie z BIP32. Ma znaczenie tylko podczas tworzenia portfela/pierwszego startu.</translation>
+ </message>
+ <message>
<source>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</source>
<translation>Węzły z białej listy nie mogą zostać zbanowane za ataki DoS, a ich transakcje będą zawsze przekazywane, nawet jeżeli będą znajdywać się już w pamięci, przydatne np. dla bramek płatniczych</translation>
</message>
diff --git a/src/qt/locale/bitcoin_pt_BR.ts b/src/qt/locale/bitcoin_pt_BR.ts
index 4d49399c11..59724318bb 100644
--- a/src/qt/locale/bitcoin_pt_BR.ts
+++ b/src/qt/locale/bitcoin_pt_BR.ts
@@ -23,7 +23,7 @@
</message>
<message>
<source>C&amp;lose</source>
- <translation>Fechar</translation>
+ <translation>&amp;Fechar</translation>
</message>
<message>
<source>Delete the currently selected address from the list</source>
@@ -39,7 +39,7 @@
</message>
<message>
<source>&amp;Delete</source>
- <translation>&amp;Excluir</translation>
+ <translation>E&amp;xcluir</translation>
</message>
<message>
<source>Choose the address to send coins to</source>
@@ -51,7 +51,7 @@
</message>
<message>
<source>C&amp;hoose</source>
- <translation>Escol&amp;ha</translation>
+ <translation>E&amp;scolha</translation>
</message>
<message>
<source>Sending addresses</source>
@@ -75,7 +75,7 @@
</message>
<message>
<source>Copy &amp;Label</source>
- <translation>Copiar rótu&amp;lo</translation>
+ <translation>Copiar &amp;rótulo</translation>
</message>
<message>
<source>&amp;Edit</source>
@@ -87,7 +87,7 @@
</message>
<message>
<source>Comma separated file (*.csv)</source>
- <translation>Comma separated file (*.csv)</translation>
+ <translation>Arquivo separado por virgula (*.csv)</translation>
</message>
<message>
<source>Exporting Failed</source>
@@ -102,7 +102,7 @@
<name>AddressTableModel</name>
<message>
<source>Label</source>
- <translation>Rótuo</translation>
+ <translation>Rótulo</translation>
</message>
<message>
<source>Address</source>
@@ -110,7 +110,7 @@
</message>
<message>
<source>(no label)</source>
- <translation>(sem rótuo)</translation>
+ <translation>(sem rótulo)</translation>
</message>
</context>
<context>
@@ -231,7 +231,7 @@
<name>BitcoinGUI</name>
<message>
<source>Sign &amp;message...</source>
- <translation>&amp;Assinar mensagem...</translation>
+ <translation>Assinar &amp;mensagem...</translation>
</message>
<message>
<source>Synchronizing with network...</source>
@@ -326,6 +326,10 @@
<translation>Clique para ativar a atividade de rede.</translation>
</message>
<message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>Sincronizando cabeçahos (%1%)...</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>Reindexando blocos no disco...</translation>
</message>
@@ -371,7 +375,7 @@
</message>
<message>
<source>&amp;Show / Hide</source>
- <translation>&amp;Exibir/Ocultar</translation>
+ <translation>&amp;Exibir / Ocultar</translation>
</message>
<message>
<source>Show or hide the main Window</source>
@@ -437,10 +441,6 @@
<source>Processing blocks on disk...</source>
<translation>Processando blocos no disco...</translation>
</message>
- <message>
- <source>No block source available...</source>
- <translation>Nenhum servidor disponível...</translation>
- </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation><numerusform>%n bloco processado do histórico de transações.</numerusform><numerusform>%n blocos processados do histórico de transações.</numerusform></translation>
@@ -479,7 +479,11 @@
</message>
<message>
<source>%1 client</source>
- <translation>%1</translation>
+ <translation>%1 cliente</translation>
+ </message>
+ <message>
+ <source>Connecting to peers...</source>
+ <translation>Conectando...</translation>
</message>
<message>
<source>Catching up...</source>
@@ -684,7 +688,7 @@
</message>
<message>
<source>(no label)</source>
- <translation>(sem rótuo)</translation>
+ <translation>(sem rótulo)</translation>
</message>
<message>
<source>change from %1 (%2)</source>
@@ -1357,6 +1361,10 @@
<translation>Nó/Serviço</translation>
</message>
<message>
+ <source>NodeId</source>
+ <translation>ID do nó</translation>
+ </message>
+ <message>
<source>Ping</source>
<translation>Ping</translation>
</message>
@@ -1896,7 +1904,7 @@
</message>
<message>
<source>Label</source>
- <translation>Rótuo</translation>
+ <translation>Rótulo</translation>
</message>
<message>
<source>Message</source>
@@ -1919,7 +1927,7 @@
</message>
<message>
<source>Label</source>
- <translation>Rótuo</translation>
+ <translation>Rótulo</translation>
</message>
<message>
<source>Message</source>
@@ -1927,7 +1935,7 @@
</message>
<message>
<source>(no label)</source>
- <translation>(sem rótuo)</translation>
+ <translation>(sem rótulo)</translation>
</message>
<message>
<source>(no message)</source>
@@ -2201,8 +2209,12 @@
<translation>Confirmar endereço de troco personalizado</translation>
</message>
<message>
+ <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source>
+ <translation>O endereço selecionado para o troco não pertence a esta carteira. Alguns ou todos os fundos da sua carteira modem ser mandados para esse endereço. Tem certeza?</translation>
+ </message>
+ <message>
<source>(no label)</source>
- <translation>(sem rótuo)</translation>
+ <translation>(sem rótulo)</translation>
</message>
</context>
<context>
@@ -2657,7 +2669,7 @@
</message>
<message>
<source>Label</source>
- <translation>Rótuo</translation>
+ <translation>Rótulo</translation>
</message>
<message numerus="yes">
<source>Open for %n more block(s)</source>
@@ -2733,7 +2745,7 @@
</message>
<message>
<source>(no label)</source>
- <translation>(sem rótuo)</translation>
+ <translation>(sem rótulo)</translation>
</message>
<message>
<source>Transaction status. Hover over this field to show number of confirmations.</source>
@@ -2880,7 +2892,7 @@
</message>
<message>
<source>Label</source>
- <translation>Rótuo</translation>
+ <translation>Rótulo</translation>
</message>
<message>
<source>Address</source>
@@ -3018,10 +3030,6 @@
<translation>Prune: A ultima sincronização da carteira foi além do dado comprimido. Você precisa reindexar (fazer o download de toda a blockchain novamente)</translation>
</message>
<message>
- <source>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, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Reduza o armazenamento de dados apagando os blocos mais antigos. Esse modo é incompatível com -txindex e -rescan. Cuidado: Reverter essa configuração requer um novo download de toda a blockchain. (Padrão: 0 = desabilitado, &gt;%u = tamanho em MiB para o uso de blocos cortados)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Rescans não são possíveis no modo prune. Você precisa usar -reindex, que irá fazer o download de toda a blockchain novamente.</translation>
</message>
@@ -3086,6 +3094,14 @@
<translation>Executa um comando quando uma transação da carteira mudar (%s no comando será substituído por TxID)</translation>
</message>
<message>
+ <source>Extra transactions to keep in memory for compact block reconstructions (default: %u)</source>
+ <translation>Transações extras para manter na memória para reconstruções de blocos compactos (padrão: %u)</translation>
+ </message>
+ <message>
+ <source>If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)</source>
+ <translation>Se este bloco está no blockchain, assume-se que ele e seus ancestrais são válidos e podem ignorar a verificação de scripts (0 para verificar todos, padrão: %s, testnet: %s)</translation>
+ </message>
+ <message>
<source>Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)</source>
<translation>A media máxima permitida de peer time compensa o ajuste. Perspectiva local de horário pode ser influenciada por pares à frente ou atrás neste montante. (padrão: %u segundos)</translation>
</message>
@@ -3102,6 +3118,14 @@
<translation>Por favor contribua se você entender que %s é útil. Visite %s para mais informações sobre o software.</translation>
</message>
<message>
+ <source>Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, &gt;%u = automatically prune block files to stay under the specified target size in MiB)</source>
+ <translation>Reduz o requerimente de espaço habiitando o pruning (apagando) blocos antigos. Isso permite o chamar o comando pruneblockchain via RPC para apagar blocos específicos, e habiita o pruning automático de blocos antigos se o tamanho em MiB for atingido. Esse modo é incompatíve com -txindex e -rescan. Aviso: Reverter essa configuração requer re-baixar o blockchain inteiro. (padrão: 0 = disabilitado, 1 = permite o pruning manua via RPC, &gt;%u = pruna os blocos para ficar abaixo do expecificado, em MiB)</translation>
+ </message>
+ <message>
+ <source>Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)</source>
+ <translation>Taxa (em %s/KiB) a ser adicionada às transações que você mandar (padrão: %s)</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>Define o número de threads de verificação de script (%u a %d, 0 = automático, &lt;0 = número de cores deixados livres, padrão: %d)</translation>
</message>
@@ -3122,6 +3146,10 @@
<translation>Use UPnP para mapear a porta escutada (padrão: 1 quando escutando e sem -proxy)</translation>
</message>
<message>
+ <source>Username and hashed password for JSON-RPC connections. The field &lt;userpw&gt; comes in the format: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=&lt;USERNAME&gt;/rpcpassword=&lt;PASSWORD&gt; pair of arguments. This option can be specified multiple times</source>
+ <translation>Nome de usuário e hash da senha para conexões JSON-RPC. O campo &lt;userpw&gt; vem com o formato: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. Um script python canônico é incluído em share/rpcuser. O cliente pode conectar normalmente usando o rpcuser=&lt;USERNAME&gt;/rpcpassword=&lt;PASSWORD&gt;. Esta opção pode ser especificado multiplas vezes</translation>
+ </message>
+ <message>
<source>Wallet will not create transactions that violate mempool chain limits (default: %u)</source>
<translation>A carteira não irá criar transações que vioem o imite de memória (padrão: %u)</translation>
</message>
@@ -3774,6 +3802,10 @@
<translation>Retransmitir P2SH não multisig (padrão: %u)</translation>
</message>
<message>
+ <source>Send transactions with full-RBF opt-in enabled (default: %u)</source>
+ <translation>Ativar opção full-RBF nas transações enviadas (padrão: %u)</translation>
+ </message>
+ <message>
<source>Set key pool size to &lt;n&gt; (default: %u)</source>
<translation>Defina o tamanho da chave para piscina&lt;n&gt; (padrão: %u)</translation>
</message>
@@ -3795,7 +3827,7 @@
</message>
<message>
<source>Specify pid file (default: %s)</source>
- <translation>Especificar aqrquivo pid (padrão: %s)</translation>
+ <translation>Especificar arquivo pid (padrão: %s)</translation>
</message>
<message>
<source>Spend unconfirmed change when sending transactions (default: %u)</source>
diff --git a/src/qt/locale/bitcoin_pt_PT.ts b/src/qt/locale/bitcoin_pt_PT.ts
index 7bfb3e710d..a45bb59239 100644
--- a/src/qt/locale/bitcoin_pt_PT.ts
+++ b/src/qt/locale/bitcoin_pt_PT.ts
@@ -62,6 +62,14 @@
<translation>A receber endereços</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>Estes são os seus endereços Bitcoin para enviar pagamentos. Verifique sempre o valor e o endereço de envio antes de enviar moedas.</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>Estes são os seus endereços Bitcoin para receber pagamentos. É recomendado que utilize um endereço novo para cada transacção.</translation>
+ </message>
+ <message>
<source>&amp;Copy Address</source>
<translation>&amp;Copiar Endereço</translation>
</message>
@@ -172,10 +180,22 @@
<translation>Carteira encriptada</translation>
</message>
<message>
+ <source>%1 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>%1 irá agora ser fechado para terminar o processo de encriptação. Recorde que a encriptação da sua carteira não protegerá totalmente os seus bitcoins de serem roubados por programas maliciosos que infectem o seu computador.</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: Qualquer cópia de segurança da carteira anterior deverá ser substituída com o novo ficheiro de carteira, agora encriptado. Por razões de segurança, cópias de segurança não encriptadas tornar-se-ão inúteis assim que começar a usar a nova carteira encriptada.</translation>
+ </message>
+ <message>
<source>Wallet encryption failed</source>
<translation>Encriptação da carteira falhou</translation>
</message>
<message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>A encriptação da carteira falhou devido a um erro interno. A carteira não foi encriptada.</translation>
+ </message>
+ <message>
<source>The supplied passphrases do not match.</source>
<translation>As frases de segurança fornecidas não coincidem.</translation>
</message>
@@ -184,6 +204,10 @@
<translation>Desbloqueio da carteira falhou</translation>
</message>
<message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>A frase de segurança introduzida para a desencriptação da carteira estava incorreta.</translation>
+ </message>
+ <message>
<source>Wallet decryption failed</source>
<translation>Desencriptação da carteira falhou</translation>
</message>
@@ -306,6 +330,10 @@
<translation>Clique para ativar novamente a atividade de rede.</translation>
</message>
<message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>A sincronizar cabeçalhos (%1%)...</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>A reindexar os blocos no disco...</translation>
</message>
@@ -417,10 +445,6 @@
<source>Processing blocks on disk...</source>
<translation>A processar blocos no disco...</translation>
</message>
- <message>
- <source>No block source available...</source>
- <translation>Nenhuma fonte de blocos disponível...</translation>
- </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation><numerusform>Processado %n bloco do histórico de transações.</numerusform><numerusform>Processados %n blocos do histórico de transações.</numerusform></translation>
@@ -454,10 +478,18 @@
<translation>Atualizado</translation>
</message>
<message>
+ <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
+ <translation>Mostrar a mensagem de ajuda %1 para obter uma lista com possíveis opções a usar na linha de comandos.</translation>
+ </message>
+ <message>
<source>%1 client</source>
<translation>Cliente %1</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>Conectando-se a pares...</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>Recuperando o atraso...</translation>
</message>
@@ -515,7 +547,11 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>A carteira está &lt;b&gt;encriptada&lt;/b&gt; e atualmente &lt;b&gt;bloqueada&lt;/b&gt;</translation>
</message>
- </context>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>Ocorreu um erro fatal. O Bitcoin não pode continuar com segurança e irá fechar.</translation>
+ </message>
+</context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -627,6 +663,10 @@
<translation>Copiar bytes</translation>
</message>
<message>
+ <source>Copy dust</source>
+ <translation>Copiar poeira</translation>
+ </message>
+ <message>
<source>Copy change</source>
<translation>Copiar troco</translation>
</message>
@@ -643,6 +683,14 @@
<translation>não</translation>
</message>
<message>
+ <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
+ <translation>Esta etiqueta fica vermelha se qualquer recipiente receber uma quantia menor que o limite da poeira.</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation>Pode variar +/- %1 satoshi(s) por input.</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(sem etiqueta)</translation>
</message>
@@ -678,6 +726,30 @@
<translation>E&amp;ndereço</translation>
</message>
<message>
+ <source>New receiving address</source>
+ <translation>Novo endereço de depósito</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Novo endereço de envio</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Editar o endereço de depósito</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Editar o endereço de envio</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>O endereço introduzido "%1" não é um endereço bitcoin válido.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book.</source>
+ <translation>O endereço introduzido "%1" já se encontra no livro de endereços.</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation>Não foi possível desbloquear a carteira.</translation>
</message>
@@ -775,6 +847,10 @@
<translation>Bem-vindo ao %1.</translation>
</message>
<message>
+ <source>%1 will download and store a copy of the Bitcoin block chain. At least %2GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory.</source>
+ <translation>O %1 irá transferir e armazenar uma cópia da blockchain. Pelo menos %2GB serão armazenados neste diretório, sendo que o valor irá crescer ao longo do tempo. A carteira também será armazenada neste mesmo diretório.</translation>
+ </message>
+ <message>
<source>Use the default data directory</source>
<translation>Utilizar a pasta de dados predefinida</translation>
</message>
@@ -806,6 +882,14 @@
<translation>Formulário</translation>
</message>
<message>
+ <source>Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source>
+ <translation>Transações recentes podem não ser visíveis por agora, portanto o saldo da sua carteira pode estar incorreto. Esta informação será corrigida quando a sua carteira acabar de sincronizar com a rede, como está explicado em baixo.</translation>
+ </message>
+ <message>
+ <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source>
+ <translation>Tentar enviar bitcoins que estão afetadas por transações ainda não exibidas não será aceite pela rede.</translation>
+ </message>
+ <message>
<source>Number of blocks left</source>
<translation>Número de blocos restantes</translation>
</message>
@@ -822,6 +906,10 @@
<translation>Progresso</translation>
</message>
<message>
+ <source>Progress increase per hour</source>
+ <translation>Aumento horário do progresso</translation>
+ </message>
+ <message>
<source>calculating...</source>
<translation>a calcular...</translation>
</message>
@@ -1045,6 +1133,10 @@
<translation>&amp;Linguagem da interface de utilizador:</translation>
</message>
<message>
+ <source>The user interface language can be set here. This setting will take effect after restarting %1.</source>
+ <translation>A linguagem da interface do utilizador pode ser definida aqui. Esta definição entrará em efeito após reiniciar %1.</translation>
+ </message>
+ <message>
<source>&amp;Unit to show amounts in:</source>
<translation>&amp;Unidade para mostrar quantias:</translation>
</message>
@@ -1175,10 +1267,42 @@
<translation>Erro do pedido de pagamento</translation>
</message>
<message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation>Impossível iniciar o controlador de bitcoin: click-to-pay</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation>Manuseamento de URI</translation>
+ </message>
+ <message>
+ <source>Payment request fetch URL is invalid: %1</source>
+ <translation>O URL do pedido de pagamento é inválido: %1</translation>
+ </message>
+ <message>
+ <source>Invalid payment address %1</source>
+ <translation>Endereço de pagamento inválido %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 não foi lido correctamente! Isto pode ser causado por um endereço Bitcoin inválido ou por parâmetros URI malformados.</translation>
+ </message>
+ <message>
+ <source>Payment request file handling</source>
+ <translation>Controlo de pedidos de pagamento.</translation>
+ </message>
+ <message>
+ <source>Payment request file cannot be read! This can be caused by an invalid payment request file.</source>
+ <translation>O ficheiro de pedido de pagamento não pôde ser lido! Isto pode ter sido causado por um ficheiro de pedido de pagamento inválido.</translation>
+ </message>
+ <message>
<source>Payment request rejected</source>
<translation>Pedido de pagamento rejeitado</translation>
</message>
<message>
+ <source>Payment request network doesn't match client network.</source>
+ <translation>Rede de requisição de pagamento não corresponde com a rede do cliente.</translation>
+ </message>
+ <message>
<source>Payment request expired.</source>
<translation>Pedido de pagamento expirado.</translation>
</message>
@@ -1187,18 +1311,46 @@
<translation>O pedido de pagamento não foi inicializado.</translation>
</message>
<message>
+ <source>Unverified payment requests to custom payment scripts are unsupported.</source>
+ <translation>Pedidos de pagamento não-verificados para scripts de pagamento personalizados não são suportados.</translation>
+ </message>
+ <message>
<source>Invalid payment request.</source>
<translation>Pedido de pagamento inválido.</translation>
</message>
<message>
+ <source>Requested payment amount of %1 is too small (considered dust).</source>
+ <translation>Quantia solicitada para pagamento de %1 é muito pequena (considerada "pó").</translation>
+ </message>
+ <message>
<source>Refund from %1</source>
<translation>Reembolso de %1</translation>
</message>
<message>
+ <source>Payment request %1 is too large (%2 bytes, allowed %3 bytes).</source>
+ <translation>Pedido de pagamento %1 é demasiado grande (%2 bytes, permitido %3 bytes).</translation>
+ </message>
+ <message>
<source>Error communicating with %1: %2</source>
<translation>Erro ao comunicar com %1: %2</translation>
</message>
- </context>
+ <message>
+ <source>Payment request cannot be parsed!</source>
+ <translation>O pedido de pagamento não pode ser lido ou processado!</translation>
+ </message>
+ <message>
+ <source>Bad response from server %1</source>
+ <translation>Má resposta do servidor %1</translation>
+ </message>
+ <message>
+ <source>Network request error</source>
+ <translation>Erro de pedido de rede</translation>
+ </message>
+ <message>
+ <source>Payment acknowledged</source>
+ <translation>Pagamento confirmado</translation>
+ </message>
+</context>
<context>
<name>PeerTableModel</name>
<message>
@@ -1209,7 +1361,15 @@
<source>Node/Service</source>
<translation>Nó/Serviço</translation>
</message>
- </context>
+ <message>
+ <source>NodeId</source>
+ <translation>NodeId</translation>
+ </message>
+ <message>
+ <source>Ping</source>
+ <translation>Latência</translation>
+ </message>
+</context>
<context>
<name>QObject</name>
<message>
@@ -1248,17 +1408,73 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation><numerusform>%n segundo</numerusform><numerusform>%n segundos</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation><numerusform>%n minuto</numerusform><numerusform>%n minutos</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation><numerusform>%n hora</numerusform><numerusform>%n horas</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation><numerusform>%n dia</numerusform><numerusform>%n dias</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation><numerusform>%n semana</numerusform><numerusform>%n semanas</numerusform></translation>
+ </message>
<message>
<source>%1 and %2</source>
<translation>%1 e %2</translation>
</message>
- </context>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation><numerusform>%n anos</numerusform><numerusform>%n anos</numerusform></translation>
+ </message>
+ <message>
+ <source>%1 didn't yet exit safely...</source>
+ <translation>%1 ainda não foi fechado em segurança...</translation>
+ </message>
+</context>
<context>
<name>QObject::QObject</name>
- </context>
+ <message>
+ <source>Error: Specified data directory "%1" does not exist.</source>
+ <translation>Erro: Pasta de dados especificada "%1" não existe.</translation>
+ </message>
+ <message>
+ <source>Error: Cannot parse configuration file: %1. Only use key=value syntax.</source>
+ <translation>Erro: não é possível analisar o ficheiro de configuração: %1. Utilize apenas a sintaxe key=value.</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation>Erro: %1</translation>
+ </message>
+</context>
<context>
<name>QRImageWidget</name>
- </context>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;Guardar Imagem...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>&amp;Copiar Imagem</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>Guardar o código QR</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>Imagem PNG (*.png)</translation>
+ </message>
+</context>
<context>
<name>RPCConsole</name>
<message>
@@ -1286,6 +1502,10 @@
<translation>Versão BerkeleyDB em uso</translation>
</message>
<message>
+ <source>Datadir</source>
+ <translation>Datadir</translation>
+ </message>
+ <message>
<source>Startup time</source>
<translation>Hora de Arranque</translation>
</message>
@@ -1370,6 +1590,10 @@
<translation>Agente Usuário</translation>
</message>
<message>
+ <source>Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</source>
+ <translation>Abrir o ficheiro de registo de depuração %1 da pasta de dados actual. Isto pode demorar alguns segundos para ficheiros de registo maiores.</translation>
+ </message>
+ <message>
<source>Decrease font size</source>
<translation>Diminuir tamanho da letra</translation>
</message>
@@ -1410,6 +1634,10 @@
<translation>Espera do Ping</translation>
</message>
<message>
+ <source>Min Ping</source>
+ <translation>Latência mínima</translation>
+ </message>
+ <message>
<source>Time Offset</source>
<translation>Fuso Horário</translation>
</message>
@@ -1470,6 +1698,14 @@
<translation>1 &amp;ano</translation>
</message>
<message>
+ <source>Ban for</source>
+ <translation>Banir para</translation>
+ </message>
+ <message>
+ <source>&amp;Unban</source>
+ <translation>&amp;Desbanir</translation>
+ </message>
+ <message>
<source>Welcome to the %1 RPC console.</source>
<translation>Bem-vindo à consola RPC da %1.</translation>
</message>
@@ -1482,6 +1718,14 @@
<translation>Insira &lt;b&gt;help&lt;/b&gt; para visualizar os comandos disponíveis.</translation>
</message>
<message>
+ <source>WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramification of a command.</source>
+ <translation>AVISO: Burlões têm estado ativos, tentando que utilizadores escrevam comandos aqui para lhes roubar as carteiras. Não utilize esta consola sem perceber perfeitamente as ramificações de um comando.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled</source>
+ <translation>Atividade de rede desativada</translation>
+ </message>
+ <message>
<source>%1 B</source>
<translation>%1 B</translation>
</message>
@@ -1601,10 +1845,18 @@
<translation>Remover</translation>
</message>
<message>
+ <source>Copy URI</source>
+ <translation>Copiar URI</translation>
+ </message>
+ <message>
<source>Copy label</source>
<translation>Copiar etiqueta</translation>
</message>
<message>
+ <source>Copy message</source>
+ <translation>Copiar mensagem</translation>
+ </message>
+ <message>
<source>Copy amount</source>
<translation>Copiar valor</translation>
</message>
@@ -1628,6 +1880,18 @@
<translation>&amp;Salvar Imagem...</translation>
</message>
<message>
+ <source>Request payment to %1</source>
+ <translation>Requisitar Pagamento para %1</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>Informação de Pagamento</translation>
+ </message>
+ <message>
+ <source>URI</source>
+ <translation>URI</translation>
+ </message>
+ <message>
<source>Address</source>
<translation>Endereço</translation>
</message>
@@ -1639,18 +1903,50 @@
<source>Label</source>
<translation>Etiqueta</translation>
</message>
- </context>
+ <message>
+ <source>Message</source>
+ <translation>Mensagem</translation>
+ </message>
+ <message>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation>URI resultante muito longo. Tente reduzir o texto do rótulo / mensagem.</translation>
+ </message>
+ <message>
+ <source>Error encoding URI into QR Code.</source>
+ <translation>Erro ao codificar URI em Código QR.</translation>
+ </message>
+</context>
<context>
<name>RecentRequestsTableModel</name>
<message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>Etiqueta</translation>
</message>
<message>
+ <source>Message</source>
+ <translation>Mensagem </translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(sem etiqueta)</translation>
</message>
- </context>
+ <message>
+ <source>(no message)</source>
+ <translation>(sem mensagem)</translation>
+ </message>
+ <message>
+ <source>(no amount requested)</source>
+ <translation>(sem quantia pedida)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation>Solicitado</translation>
+ </message>
+</context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1778,6 +2074,10 @@
<translation>Lixo:</translation>
</message>
<message>
+ <source>Confirmation time target:</source>
+ <translation>Tempo de confirmação:</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>Limpar &amp;Tudo</translation>
</message>
@@ -1814,18 +2114,58 @@
<translation>Copiar bytes</translation>
</message>
<message>
+ <source>Copy dust</source>
+ <translation>Copiar pó</translation>
+ </message>
+ <message>
<source>Copy change</source>
<translation>Copiar troco</translation>
</message>
<message>
+ <source>%1 to %2</source>
+ <translation>%1 para %2</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to send?</source>
+ <translation>Tem a certeza que deseja enviar?</translation>
+ </message>
+ <message>
<source>added as transaction fee</source>
<translation>adicionado como taxa de transação</translation>
</message>
<message>
+ <source>Total Amount %1</source>
+ <translation>Quantia Total %1</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>ou</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation>Confirme envio de moedas</translation>
+ </message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>O endereço do destinatário é inválido. Por favor, reverifique.</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation>O valor a pagar dever maior que 0.</translation>
+ </message>
+ <message>
+ <source>The amount exceeds your balance.</source>
+ <translation>O valor excede o seu saldo.</translation>
+ </message>
+ <message>
<source>The total exceeds your balance when the %1 transaction fee is included.</source>
<translation>O total excede o seu saldo quando a taxa de transação %1 está incluída.</translation>
</message>
<message>
+ <source>Transaction creation failed!</source>
+ <translation>A criação da transação falhou!</translation>
+ </message>
+ <message>
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation>Uma taxa superior a %1 é considerada uma taxa altamente absurda.</translation>
</message>
@@ -1838,6 +2178,10 @@
<translation>Pague apenas a taxa obrigatória de %1</translation>
</message>
<message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>Aviso: endereço Bitcoin inválido</translation>
+ </message>
+ <message>
<source>Warning: Unknown change address</source>
<translation>Aviso: endereço de troco desconhecido</translation>
</message>
@@ -1931,7 +2275,11 @@
</context>
<context>
<name>SendConfirmationDialog</name>
- </context>
+ <message>
+ <source>Yes</source>
+ <translation>Sim</translation>
+ </message>
+</context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -2029,7 +2377,59 @@
<source>Reset all verify message fields</source>
<translation>Repor todos os campos de verificação de mensagem</translation>
</message>
- </context>
+ <message>
+ <source>Click "Sign Message" to generate signature</source>
+ <translation>Clique "Assinar Mensagem" para gerar a assinatura</translation>
+ </message>
+ <message>
+ <source>The entered address is invalid.</source>
+ <translation>O endereço introduzido é inválido.</translation>
+ </message>
+ <message>
+ <source>Please check the address and try again.</source>
+ <translation>Por favor, verifique o endereço e tente novamente.</translation>
+ </message>
+ <message>
+ <source>The entered address does not refer to a key.</source>
+ <translation>O endereço introduzido não refere-se a nenhuma chave.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock was cancelled.</source>
+ <translation>O desbloqueio da carteira foi cancelado.</translation>
+ </message>
+ <message>
+ <source>Private key for the entered address is not available.</source>
+ <translation>A chave privada para o endereço introduzido não está disponível.</translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation>Assinatura da mensagem falhou.</translation>
+ </message>
+ <message>
+ <source>Message signed.</source>
+ <translation>Mensagem assinada.</translation>
+ </message>
+ <message>
+ <source>The signature could not be decoded.</source>
+ <translation>Não foi possível descodificar a assinatura.</translation>
+ </message>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation>Por favor, verifique a assinatura e tente novamente.</translation>
+ </message>
+ <message>
+ <source>The signature did not match the message digest.</source>
+ <translation>A assinatura não corresponde com o conteúdo da mensagem.</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation>Verificação da mensagem falhou.</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation>Mensagem verificada.</translation>
+ </message>
+</context>
<context>
<name>SplashScreen</name>
<message>
@@ -2047,35 +2447,311 @@
<context>
<name>TransactionDesc</name>
<message>
+ <source>Open until %1</source>
+ <translation>Aberto até %1</translation>
+ </message>
+ <message>
+ <source>%1/offline</source>
+ <translation>%1/off-line</translation>
+ </message>
+ <message>
+ <source>0/unconfirmed, %1</source>
+ <translation>0/não confirmada, %1</translation>
+ </message>
+ <message>
+ <source>in memory pool</source>
+ <translation>no banco de memória</translation>
+ </message>
+ <message>
+ <source>not in memory pool</source>
+ <translation>não está no banco de memória</translation>
+ </message>
+ <message>
+ <source>abandoned</source>
+ <translation>abandonada</translation>
+ </message>
+ <message>
+ <source>%1/unconfirmed</source>
+ <translation>%1/não confirmada</translation>
+ </message>
+ <message>
+ <source>%1 confirmations</source>
+ <translation>%1 confirmações</translation>
+ </message>
+ <message>
+ <source>Status</source>
+ <translation>Estado</translation>
+ </message>
+ <message>
+ <source>, has not been successfully broadcast yet</source>
+ <translation>, ainda não foi transmitido com sucesso</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Source</source>
+ <translation>Origem</translation>
+ </message>
+ <message>
+ <source>Generated</source>
+ <translation>Gerado</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>De</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>desconhecido</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation>Para</translation>
+ </message>
+ <message>
+ <source>own address</source>
+ <translation>endereço próprio</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>vigiar apenas</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>etiqueta</translation>
+ </message>
+ <message>
+ <source>Credit</source>
+ <translation>Crédito</translation>
+ </message>
+ <message>
+ <source>not accepted</source>
+ <translation>não aceite</translation>
+ </message>
+ <message>
+ <source>Debit</source>
+ <translation>Débito</translation>
+ </message>
+ <message>
+ <source>Total debit</source>
+ <translation>Débito total</translation>
+ </message>
+ <message>
+ <source>Total credit</source>
+ <translation>Crédito total</translation>
+ </message>
+ <message>
<source>Transaction fee</source>
<translation>Taxa de transação</translation>
</message>
<message>
+ <source>Net amount</source>
+ <translation>Valor líquido</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Mensagem</translation>
+ </message>
+ <message>
+ <source>Comment</source>
+ <translation>Comentário</translation>
+ </message>
+ <message>
+ <source>Transaction ID</source>
+ <translation>Id. da Transação</translation>
+ </message>
+ <message>
+ <source>Transaction total size</source>
+ <translation>Tamanho total da transição</translation>
+ </message>
+ <message>
+ <source>Output index</source>
+ <translation>Índex de saída</translation>
+ </message>
+ <message>
+ <source>Merchant</source>
+ <translation>Comerciante</translation>
+ </message>
+ <message>
+ <source>Debug information</source>
+ <translation>Informação de depuração</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation>Transação</translation>
+ </message>
+ <message>
+ <source>Inputs</source>
+ <translation>Entradas</translation>
+ </message>
+ <message>
<source>Amount</source>
<translation>Valor</translation>
</message>
- </context>
+ <message>
+ <source>true</source>
+ <translation>verdadeiro</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation>falso</translation>
+ </message>
+</context>
<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Esta janela mostra uma descrição detalhada da transação</translation>
</message>
- </context>
+ <message>
+ <source>Details for %1</source>
+ <translation>Detalhes para %1</translation>
+ </message>
+</context>
<context>
<name>TransactionTableModel</name>
<message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Tipo</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>Etiqueta</translation>
</message>
<message>
+ <source>Open until %1</source>
+ <translation>Aberto até %1</translation>
+ </message>
+ <message>
+ <source>Offline</source>
+ <translation>Off-line</translation>
+ </message>
+ <message>
+ <source>Unconfirmed</source>
+ <translation>Não confirmado</translation>
+ </message>
+ <message>
+ <source>Abandoned</source>
+ <translation>Anbandonada</translation>
+ </message>
+ <message>
+ <source>Confirmed (%1 confirmations)</source>
+ <translation>Confirmada (%1 confirmações)</translation>
+ </message>
+ <message>
+ <source>Conflicted</source>
+ <translation>Incompatível</translation>
+ </message>
+ <message>
+ <source>Generated but not accepted</source>
+ <translation>Gerada mas não aceite</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Recebido com</translation>
+ </message>
+ <message>
+ <source>Received from</source>
+ <translation>Recebido de</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Enviado para</translation>
+ </message>
+ <message>
+ <source>Payment to yourself</source>
+ <translation>Pagamento para si mesmo</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Minada</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>vigiar apenas</translation>
+ </message>
+ <message>
+ <source>(n/a)</source>
+ <translation>(n/d)</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(sem etiqueta)</translation>
</message>
+ <message>
+ <source>Transaction status. Hover over this field to show number of confirmations.</source>
+ <translation>Estado da transação. Passar o cursor por cima deste campo para mostrar o número de confirmações.</translation>
+ </message>
+ <message>
+ <source>Type of transaction.</source>
+ <translation>Tipo de transação.</translation>
+ </message>
</context>
<context>
<name>TransactionView</name>
<message>
+ <source>All</source>
+ <translation>Todas</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>Hoje</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>Esta semana</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>Este mês</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>Mês passado</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>Este ano</translation>
+ </message>
+ <message>
+ <source>Range...</source>
+ <translation>Período...</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Recebido com</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Enviado para</translation>
+ </message>
+ <message>
+ <source>To yourself</source>
+ <translation>Para si mesmo</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Minada</translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation>Outras</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation>Valor mín.</translation>
+ </message>
+ <message>
+ <source>Abandon transaction</source>
+ <translation>Abandonar transação</translation>
+ </message>
+ <message>
<source>Copy address</source>
<translation>Copiar endereço</translation>
</message>
@@ -2092,10 +2768,46 @@
<translation>Copiar Id. da transação</translation>
</message>
<message>
+ <source>Copy raw transaction</source>
+ <translation>Copiar transação em bruto</translation>
+ </message>
+ <message>
+ <source>Copy full transaction details</source>
+ <translation>Copiar detalhes completos da transação</translation>
+ </message>
+ <message>
+ <source>Edit label</source>
+ <translation>Editar etiqueta</translation>
+ </message>
+ <message>
+ <source>Show transaction details</source>
+ <translation>Mostrar detalhes da transação</translation>
+ </message>
+ <message>
+ <source>Export Transaction History</source>
+ <translation>Exportar Histórico de Transacções</translation>
+ </message>
+ <message>
<source>Comma separated file (*.csv)</source>
<translation>Ficheiro separado por vírgulas (*.csv)</translation>
</message>
<message>
+ <source>Confirmed</source>
+ <translation>Confirmada</translation>
+ </message>
+ <message>
+ <source>Watch-only</source>
+ <translation>Vigiar apenas</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Data</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Tipo</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>Etiqueta</translation>
</message>
@@ -2104,10 +2816,26 @@
<translation>Endereço</translation>
</message>
<message>
+ <source>ID</source>
+ <translation>Id.</translation>
+ </message>
+ <message>
<source>Exporting Failed</source>
<translation>Exportação Falhou</translation>
</message>
- </context>
+ <message>
+ <source>Exporting Successful</source>
+ <translation>Exportação Bem Sucedida</translation>
+ </message>
+ <message>
+ <source>Range:</source>
+ <translation>Período:</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>até</translation>
+ </message>
+</context>
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
@@ -2120,13 +2848,41 @@
</context>
<context>
<name>WalletModel</name>
- </context>
+ <message>
+ <source>Send Coins</source>
+ <translation>Enviar Moedas</translation>
+ </message>
+</context>
<context>
<name>WalletView</name>
<message>
+ <source>&amp;Export</source>
+ <translation>&amp;Exportar</translation>
+ </message>
+ <message>
<source>Export the data in the current tab to a file</source>
<translation>Exportar os dados no separador atual para um ficheiro</translation>
</message>
+ <message>
+ <source>Backup Wallet</source>
+ <translation>Cópia de Segurança da Carteira</translation>
+ </message>
+ <message>
+ <source>Wallet Data (*.dat)</source>
+ <translation>Dados da Carteira (*.dat)</translation>
+ </message>
+ <message>
+ <source>Backup Failed</source>
+ <translation>Cópia de Segurança Falhou</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the wallet data to %1.</source>
+ <translation>Ocorreu um erro ao tentar guardar os dados da carteira em %1.</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation>Cópia de Segurança Bem Sucedida</translation>
+ </message>
</context>
<context>
<name>bitcoin-core</name>
@@ -2163,10 +2919,6 @@
<translation>Suprimir: a última sincronização da carteira vai além dos dados suprimidos. O que precisa para -reindex (transferir novamente toda a cadeia de blocos, no caso de nó suprimido)</translation>
</message>
<message>
- <source>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, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Reduza os requisitos de armazenamento podando (eliminando) blocos antigos. Este modo é incompatível com -txindex e -rescan. Aviso: Reverter esta opção requer um novo descarregamento da cadeia de blocos completa. (padrão: 0 = desactivar poda de blocos, &gt;%u = tamanho desejado em MiB para utilizar em ficheiros de blocos)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Reanálises não são possíveis no modo de suprimir. Para isso terá de utilizar -reindex que irá transferir novamente toda a cadeia de blocos.</translation>
</message>
@@ -2195,6 +2947,10 @@
<translation>Bitcoin Core</translation>
</message>
<message>
+ <source>The %s developers</source>
+ <translation>Os programadores de %s</translation>
+ </message>
+ <message>
<source>A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)</source>
<translation>Uma percentagem da taxa (em %s/kB) que será utilizada quando a estimativa da taxa tiver dados insuficientes (predefinição: %s)</translation>
</message>
@@ -2227,6 +2983,14 @@
<translation>Utilizar UPnP para mapear a porta de escuta (predefinição: 1 quando escutar e sem -proxy)</translation>
</message>
<message>
+ <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
+ <translation>Aviso: A rede não parece estar completamente de acordo! Parece que alguns mineiros estão com dificuldades técnicas.</translation>
+ </message>
+ <message>
+ <source>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source>
+ <translation>Aviso: Parecemos não estar de acordo com os nossos pares! Poderá ter que atualizar o seu cliente, ou outros nós poderão ter que atualizar os seus clientes.</translation>
+ </message>
+ <message>
<source>-maxmempool must be at least %d MB</source>
<translation>- máximo do banco de memória deverá ser pelo menos %d MB</translation>
</message>
@@ -2247,10 +3011,22 @@
<translation>Opções da criação de bloco:</translation>
</message>
<message>
+ <source>Cannot resolve -%s address: '%s'</source>
+ <translation>Não é possível resolver -%s endereço '%s'</translation>
+ </message>
+ <message>
+ <source>Chain selection options:</source>
+ <translation>Opções de seleção da cadeia:</translation>
+ </message>
+ <message>
<source>Connection options:</source>
<translation>Opções de ligação:</translation>
</message>
<message>
+ <source>Copyright (C) %i-%i</source>
+ <translation>Direitos de Autor (C) %i-%i</translation>
+ </message>
+ <message>
<source>Corrupted block database detected</source>
<translation>Cadeia de blocos corrompida detectada</translation>
</message>
@@ -2347,6 +3123,10 @@
<translation>Manter o banco de memória da transação abaixo de &lt;n&gt; megabytes (predefinição: %u)</translation>
</message>
<message>
+ <source>Loading banlist...</source>
+ <translation>A carregar a lista de banir...</translation>
+ </message>
+ <message>
<source>Location of the auth cookie (default: data dir)</source>
<translation>Localização de cookie de autorização (predefinição: diretoria de dados)</translation>
</message>
@@ -2403,6 +3183,10 @@
<translation>Utilizar UPnP para mapear a porta de escuta (predefinição: %u)</translation>
</message>
<message>
+ <source>Use the test chain</source>
+ <translation>Utilize a cadeia de testes</translation>
+ </message>
+ <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation>Comentário no User Agent (%s) contém caracteres inseguros.</translation>
</message>
@@ -2419,6 +3203,10 @@
<translation>A carteira %s reside fora da pasta de dados %s</translation>
</message>
<message>
+ <source>Wallet debugging/testing options:</source>
+ <translation>Opções de depuração/testes da carteira:</translation>
+ </message>
+ <message>
<source>Wallet options:</source>
<translation>Opções da carteira:</translation>
</message>
@@ -2679,6 +3467,14 @@
<translation>Suportar filtragem de blocos e transacções com fitros bloom (padrão: %u)</translation>
</message>
<message>
+ <source>This is the transaction fee you may pay when fee estimates are not available.</source>
+ <translation>Esta é a taxa de transação que poderá pagar quando as estimativas da taxa não estão disponíveis.</translation>
+ </message>
+ <message>
+ <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit %s and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
+ <translation>Este produto inclui software desenvolvido pelo Projeto de OpenSSL para utilização no OpenSSL Toolkit %s e software criptográfico escrito por Eric Young e software UPnP escrito por Thomas Bernard.</translation>
+ </message>
+ <message>
<source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source>
<translation>Comprimento total da entrada da versão de rede (%i) excede o comprimento máximo (%i). Reduzir o número ou o tamanho de uacomments.</translation>
</message>
@@ -2783,10 +3579,26 @@
<translation>Gastar o troco não confirmado quando enviar transações (predefinição: %u)</translation>
</message>
<message>
+ <source>This is the transaction fee you will pay if you send a transaction.</source>
+ <translation>Esta é a taxa de transação que irá pagar se enviar uma transação.</translation>
+ </message>
+ <message>
<source>Threshold for disconnecting misbehaving peers (default: %u)</source>
<translation>Tolerância para desligar nós com comportamento indesejável (padrão: %u)</translation>
</message>
<message>
+ <source>Transaction amounts must not be negative</source>
+ <translation>Os valores da transação não devem ser negativos</translation>
+ </message>
+ <message>
+ <source>Transaction has too long of a mempool chain</source>
+ <translation>A transação é muito grande de uma cadeia do banco de memória</translation>
+ </message>
+ <message>
+ <source>Transaction must have at least one recipient</source>
+ <translation>A transação dever pelo menos um destinatário</translation>
+ </message>
+ <message>
<source>Unknown network specified in -onlynet: '%s'</source>
<translation>Rede desconhecida especificada em -onlynet: '%s'</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ro_RO.ts b/src/qt/locale/bitcoin_ro_RO.ts
index 92fc87f4f2..3d3a4b0431 100644
--- a/src/qt/locale/bitcoin_ro_RO.ts
+++ b/src/qt/locale/bitcoin_ro_RO.ts
@@ -253,10 +253,6 @@
<source>%n active connection(s) to Bitcoin network</source>
<translation><numerusform>%n conexiune activă către reţeaua Bitcoin</numerusform><numerusform>%n conexiuni active către reţeaua Bitcoin</numerusform><numerusform>%n de conexiuni active către reţeaua Bitcoin</numerusform></translation>
</message>
- <message>
- <source>No block source available...</source>
- <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>
diff --git a/src/qt/locale/bitcoin_ru.ts b/src/qt/locale/bitcoin_ru.ts
index 11fa2f7fea..7d013416ff 100644
--- a/src/qt/locale/bitcoin_ru.ts
+++ b/src/qt/locale/bitcoin_ru.ts
@@ -63,7 +63,7 @@
</message>
<message>
<source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
- <translation>Это ваши адреса Bitcoin для отправки платежей. Всегда проверяйте количество и адрес получателя перед отправкой перевода.</translation>
+ <translation>Это ваши адреса Bitcoin для отправки платежей. Всегда проверяйте сумму и адрес получателя перед отправкой перевода.</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>
@@ -330,6 +330,10 @@
<translation>Кликните, чтобы снова разрешить сетевую активность.</translation>
</message>
<message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>Синхронизация заголовков (%1%)...</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>Идёт переиндексация блоков на диске...</translation>
</message>
@@ -441,10 +445,6 @@
<source>Processing blocks on disk...</source>
<translation>Обработка блоков на диске...</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>
@@ -486,6 +486,10 @@
<translation>%1 клиент</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>Подключение к пирам...</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>Синхронизируется...</translation>
</message>
@@ -3030,10 +3034,6 @@
<translation>Удаление: последняя синхронизация кошелька вышла за рамки удаленных данных. Вам нужен -reindex (скачать всю цепь блоков в случае удаленного узла)</translation>
</message>
<message>
- <source>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, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Уменьшить размер хранилища за счёт удаления (обрезания) старых блоков. Этот режим несовместим с -txindex и -rescan. Внимание: переключение этой опции обратно потребует полной загрузки цепи блоков. (по умолчанию: 0 = отключить удаление блоков, &gt;%u = целевой размер в Мб для файлов блоков)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Повторное сканирование не возможно в режиме удаления. Вам надо будет использовать -reindex, который загрузит заново всю цепь блоков.</translation>
</message>
@@ -3094,6 +3094,14 @@
<translation>Выполнить команду, когда меняется транзакция в бумажнике (%s в команде заменяется на TxID)</translation>
</message>
<message>
+ <source>Extra transactions to keep in memory for compact block reconstructions (default: %u)</source>
+ <translation>Хранить в памяти дополнительные транзакции для реконструкции компактных блоков (по умолчанию: %u)</translation>
+ </message>
+ <message>
+ <source>If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)</source>
+ <translation>Если этот блок в цепи, считать его и последующие блоки верными и потенциально пропускать проверку их скриптов (0 для проверки всех, по умолчанию: %s, тестовая сеть: %s)</translation>
+ </message>
+ <message>
<source>Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)</source>
<translation>Максимально допустимое среднее отклонение времени участников. Локальное представление времени может меняться вперед или назад на это количество. (по умолчанию: %u секунд)</translation>
</message>
@@ -3110,6 +3118,14 @@
<translation>Пожалуйста, внести свой вклад, если вы найдете %s полезными. Посетите %s для получения дополнительной информации о программном обеспечении.</translation>
</message>
<message>
+ <source>Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, &gt;%u = automatically prune block files to stay under the specified target size in MiB)</source>
+ <translation>Уменьшить размер хранилища за счёт обрезания (удаления) старых блоков. Будет разрешён вызов RPC метода pruneblockchain для удаления определённых блоков и разрешено автоматическое обрезание старых блоков, если указан целевой размер в Мб. Этот режим несовместим с -txindex и -rescan. Внимание: переключение этой опции обратно потребует полной загрузки цепи блоков. (по умолчанию: 0 = отключить обрезание блоков, 1 = разрешить ручное обрезание через RPC, &gt;%u = автоматически обрезать файлы блоков, чтобы они были меньше указанного размера в Мб)</translation>
+ </message>
+ <message>
+ <source>Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)</source>
+ <translation>Задать минимальный курс комиссии (в %s/Кб) для транзакцийб включаемых в создаваемый блок. (по умолчанию: %s)</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>
diff --git a/src/qt/locale/bitcoin_ru_RU.ts b/src/qt/locale/bitcoin_ru_RU.ts
index 60d98c41d9..0cb0e7f6e4 100644
--- a/src/qt/locale/bitcoin_ru_RU.ts
+++ b/src/qt/locale/bitcoin_ru_RU.ts
@@ -3,7 +3,7 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation>Кликните правой кнопкой мыши для редоктирования адреса или ярлыка</translation>
+ <translation>Кликните правой кнопкой мыши для редактирования адреса или метки</translation>
</message>
<message>
<source>Create a new address</source>
@@ -15,7 +15,7 @@
</message>
<message>
<source>Copy the currently selected address to the system clipboard</source>
- <translation>Copy the currently selected address to the system clipboardый адрес в буфер</translation>
+ <translation>Скопировать текущий выбранный адрес в буфер обмена системы</translation>
</message>
<message>
<source>&amp;Copy</source>
@@ -41,16 +41,112 @@
<source>&amp;Delete</source>
<translation>Удалить</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>C&amp;hoose</source>
+ <translation>В&amp;ыбрать</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Адреса отправки</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Адреса получения</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Копировать адрес</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Копировать &amp;метку</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Редактировать</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Экспортировать список адресов</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Экспорт не удался</translation>
+ </message>
</context>
<context>
<name>AddressTableModel</name>
- </context>
+ <message>
+ <source>Label</source>
+ <translation>Метка</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Адрес</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(нет метки)</translation>
+ </message>
+</context>
<context>
<name>AskPassphraseDialog</name>
<message>
+ <source>Passphrase Dialog</source>
+ <translation>Ввод пароля</translation>
+ </message>
+ <message>
+ <source>Enter passphrase</source>
+ <translation>Введите пароль</translation>
+ </message>
+ <message>
+ <source>New passphrase</source>
+ <translation>Новый пароль</translation>
+ </message>
+ <message>
<source>Repeat new passphrase</source>
<translation>Повторите новый пароль</translation>
</message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Зашифровать бумажник</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Эта операция требует вашего пароля для разблокировки бумажника</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Разблокировать бумажник</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Расшифровать бумажник</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Изменить пароль</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Подтвердите шифрование бумажника</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Бумажник зашифрован</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Ошибка разблокировки кошелька</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
@@ -58,10 +154,114 @@
<context>
<name>BitcoinGUI</name>
<message>
+ <source>Sign &amp;message...</source>
+ <translation>Подписать &amp;сообщение...</translation>
+ </message>
+ <message>
+ <source>&amp;Transactions</source>
+ <translation>&amp;Транзакции</translation>
+ </message>
+ <message>
+ <source>Browse transaction history</source>
+ <translation>Просмотр истории транзакций</translation>
+ </message>
+ <message>
+ <source>E&amp;xit</source>
+ <translation>В&amp;ыход</translation>
+ </message>
+ <message>
+ <source>Quit application</source>
+ <translation>Выйти</translation>
+ </message>
+ <message>
+ <source>&amp;About %1</source>
+ <translation>&amp;О программе %1</translation>
+ </message>
+ <message>
+ <source>Show information about %1</source>
+ <translation>Показать информацию о %1</translation>
+ </message>
+ <message>
+ <source>About &amp;Qt</source>
+ <translation>О библиотеке &amp;Qt</translation>
+ </message>
+ <message>
+ <source>Show information about Qt</source>
+ <translation>Показать информацию о библиотеке Qt</translation>
+ </message>
+ <message>
+ <source>&amp;Options...</source>
+ <translation>&amp;Опции...</translation>
+ </message>
+ <message>
+ <source>&amp;Encrypt Wallet...</source>
+ <translation>&amp;Зашифровать кошелёк</translation>
+ </message>
+ <message>
+ <source>&amp;Backup Wallet...</source>
+ <translation>&amp;Создать резервную копию бумажника</translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase...</source>
+ <translation>&amp;Изменить пароль...</translation>
+ </message>
+ <message>
+ <source>&amp;Sending addresses...</source>
+ <translation>&amp;Адреса для отправки...</translation>
+ </message>
+ <message>
+ <source>&amp;Receiving addresses...</source>
+ <translation>&amp;Адреса для получения...</translation>
+ </message>
+ <message>
+ <source>Open &amp;URI...</source>
+ <translation>Открыть &amp;URI...</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>Синхронизация заголовков (%1%)...</translation>
+ </message>
+ <message>
+ <source>&amp;Debug window</source>
+ <translation>&amp;Окно отладки</translation>
+ </message>
+ <message>
+ <source>&amp;Verify message...</source>
+ <translation>&amp;Проверить сообщение...</translation>
+ </message>
+ <message>
<source>Bitcoin</source>
<translation>Bitcoin Core</translation>
</message>
<message>
+ <source>Wallet</source>
+ <translation>Кошелек</translation>
+ </message>
+ <message>
+ <source>&amp;Send</source>
+ <translation>&amp;Отправить</translation>
+ </message>
+ <message>
+ <source>&amp;Receive</source>
+ <translation>&amp;Получить</translation>
+ </message>
+ <message>
+ <source>&amp;Show / Hide</source>
+ <translation>&amp;Показать / Спрятать</translation>
+ </message>
+ <message>
+ <source>&amp;File</source>
+ <translation>&amp;Файл</translation>
+ </message>
+ <message>
+ <source>&amp;Settings</source>
+ <translation>&amp;Настройки</translation>
+ </message>
+ <message>
+ <source>&amp;Help</source>
+ <translation>&amp;Помощь</translation>
+ </message>
+ <message>
<source>&amp;Command-line options</source>
<translation>Опции командной строки</translation>
</message>
@@ -77,10 +277,30 @@
<source>Information</source>
<translation>Информация</translation>
</message>
+ <message>
+ <source>Up to date</source>
+ <translation>Готов</translation>
+ </message>
+ <message>
+ <source>Connecting to peers...</source>
+ <translation>Подключение к пирам...</translation>
+ </message>
</context>
<context>
<name>CoinControlDialog</name>
<message>
+ <source>Bytes:</source>
+ <translation>Байтов:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation>Количество:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation>Комиссия:</translation>
+ </message>
+ <message>
<source>Date</source>
<translation>Дата</translation>
</message>
@@ -92,6 +312,34 @@
<source>Confirmed</source>
<translation>Подтвержденные</translation>
</message>
+ <message>
+ <source>Copy address</source>
+ <translation>Копировать адрес</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Копировать метку</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Копировать сумму</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Копировать ID транзакции</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>да</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>нет</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(нет метки)</translation>
+ </message>
</context>
<context>
<name>EditAddressDialog</name>
@@ -117,16 +365,36 @@
<source>command-line options</source>
<translation>Опции командной строки</translation>
</message>
+ <message>
+ <source>Start minimized</source>
+ <translation>Запускать свернутым</translation>
+ </message>
</context>
<context>
<name>Intro</name>
<message>
+ <source>Welcome</source>
+ <translation>Добро пожаловать</translation>
+ </message>
+ <message>
+ <source>Welcome to %1.</source>
+ <translation>Добро пожаловать в %1.</translation>
+ </message>
+ <message>
<source>Error</source>
<translation>Ошибка</translation>
</message>
</context>
<context>
<name>ModalOverlay</name>
+ <message>
+ <source>Progress</source>
+ <translation>Прогресс</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Спрятать</translation>
+ </message>
</context>
<context>
<name>OpenURIDialog</name>
@@ -141,9 +409,109 @@
</context>
<context>
<name>OptionsDialog</name>
+ <message>
+ <source>Options</source>
+ <translation>Опции</translation>
+ </message>
+ <message>
+ <source>MB</source>
+ <translation>МБ</translation>
+ </message>
+ <message>
+ <source>Allow incoming connections</source>
+ <translation>Разрешить входящие соеденения</translation>
+ </message>
+ <message>
+ <source>&amp;Reset Options</source>
+ <translation>&amp;Сбросить опции</translation>
+ </message>
+ <message>
+ <source>&amp;Network</source>
+ <translation>&amp;Сеть</translation>
+ </message>
+ <message>
+ <source>W&amp;allet</source>
+ <translation>К&amp;ошелёк</translation>
+ </message>
+ <message>
+ <source>Expert</source>
+ <translation>Эксперт</translation>
+ </message>
+ <message>
+ <source>Map port using &amp;UPnP</source>
+ <translation>Пробросить порт через &amp;UPnP</translation>
+ </message>
+ <message>
+ <source>Connect to the Bitcoin network through a SOCKS5 proxy.</source>
+ <translation>Подключится к сети Bitcoin через SOCKS5 прокси.</translation>
+ </message>
+ <message>
+ <source>Proxy &amp;IP:</source>
+ <translation>IP прокси:</translation>
+ </message>
+ <message>
+ <source>&amp;Port:</source>
+ <translation>&amp;Порт:</translation>
+ </message>
+ <message>
+ <source>Port of the proxy (e.g. 9050)</source>
+ <translation>Порт прокси: (напр. 9050)</translation>
+ </message>
+ <message>
+ <source>IPv4</source>
+ <translation>IPv4</translation>
+ </message>
+ <message>
+ <source>IPv6</source>
+ <translation>IPv6</translation>
+ </message>
+ <message>
+ <source>Tor</source>
+ <translation>Tor</translation>
+ </message>
+ <message>
+ <source>&amp;Window</source>
+ <translation>&amp;Окно</translation>
+ </message>
+ <message>
+ <source>Hide tray icon</source>
+ <translation>Спрятать иконку в трее</translation>
+ </message>
+ <message>
+ <source>&amp;OK</source>
+ <translation>&amp;ОК</translation>
+ </message>
+ <message>
+ <source>&amp;Cancel</source>
+ <translation>&amp;Отмена</translation>
+ </message>
</context>
<context>
<name>OverviewPage</name>
+ <message>
+ <source>Immature:</source>
+ <translation>Незрелые:</translation>
+ </message>
+ <message>
+ <source>Balances</source>
+ <translation>Балансы</translation>
+ </message>
+ <message>
+ <source>Total:</source>
+ <translation>Всего:</translation>
+ </message>
+ <message>
+ <source>Your current total balance</source>
+ <translation>Ваш текущий баланс:</translation>
+ </message>
+ <message>
+ <source>Your current balance in watch-only addresses</source>
+ <translation>Ваш текущий баланс на адресах только для чтения:</translation>
+ </message>
+ <message>
+ <source>Recent transactions</source>
+ <translation>Последние транзакции</translation>
+ </message>
</context>
<context>
<name>PaymentServer</name>
@@ -153,43 +521,243 @@
</context>
<context>
<name>QObject</name>
+ <message>
+ <source>Enter a Bitcoin address (e.g. %1)</source>
+ <translation>Введите биткоин-адрес (напр. %1)</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>
</context>
<context>
<name>QObject::QObject</name>
- </context>
+ <message>
+ <source>Error: %1</source>
+ <translation>Ошибка: %1</translation>
+ </message>
+</context>
<context>
<name>QRImageWidget</name>
- </context>
+ <message>
+ <source>Save QR Code</source>
+ <translation>Сохранить QR-код</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>PNG Картинка (*.png)</translation>
+ </message>
+</context>
<context>
<name>RPCConsole</name>
<message>
<source>&amp;Information</source>
<translation>Информация</translation>
</message>
- </context>
+ <message>
+ <source>Debug window</source>
+ <translation>Окно отладки</translation>
+ </message>
+ <message>
+ <source>Received</source>
+ <translation>Получено</translation>
+ </message>
+ <message>
+ <source>Sent</source>
+ <translation>Отправлено</translation>
+ </message>
+ <message>
+ <source>&amp;Peers</source>
+ <translation>&amp;Пиры</translation>
+ </message>
+ <message>
+ <source>Banned peers</source>
+ <translation>Заблокированные пиры</translation>
+ </message>
+ <message>
+ <source>Version</source>
+ <translation>Версия</translation>
+ </message>
+ <message>
+ <source>&amp;Open</source>
+ <translation>&amp;Открыть</translation>
+ </message>
+ <message>
+ <source>&amp;Console</source>
+ <translation>&amp;Консоль</translation>
+ </message>
+ <message>
+ <source>1 &amp;hour</source>
+ <translation>1 &amp;час</translation>
+ </message>
+ <message>
+ <source>1 &amp;day</source>
+ <translation>1 &amp;день</translation>
+ </message>
+ <message>
+ <source>1 &amp;week</source>
+ <translation>1 &amp;неделя</translation>
+ </message>
+ <message>
+ <source>1 &amp;year</source>
+ <translation>1 &amp;год</translation>
+ </message>
+ <message>
+ <source>%1 B</source>
+ <translation>%1 Б</translation>
+ </message>
+ <message>
+ <source>%1 KB</source>
+ <translation>%1 КБ</translation>
+ </message>
+ <message>
+ <source>%1 MB</source>
+ <translation>%1 МБ</translation>
+ </message>
+ <message>
+ <source>%1 GB</source>
+ <translation>%1 ГБ</translation>
+ </message>
+ <message>
+ <source>never</source>
+ <translation>никогда</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Да</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Нет</translation>
+ </message>
+ <message>
+ <source>Unknown</source>
+ <translation>Неизвестно</translation>
+ </message>
+</context>
<context>
<name>ReceiveCoinsDialog</name>
- </context>
+ <message>
+ <source>Clear</source>
+ <translation>Отчистить</translation>
+ </message>
+ <message>
+ <source>Show</source>
+ <translation>Показать</translation>
+ </message>
+ <message>
+ <source>Remove</source>
+ <translation>Удалить</translation>
+ </message>
+ <message>
+ <source>Copy URI</source>
+ <translation>Копировать URI</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Копировать метку</translation>
+ </message>
+ <message>
+ <source>Copy message</source>
+ <translation>Копировать сообщение</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Копировать сумму</translation>
+ </message>
+</context>
<context>
<name>ReceiveRequestDialog</name>
+ <message>
+ <source>Address</source>
+ <translation>Адрес</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Метка</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Метка</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(нет метки)</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
- </context>
+ <message>
+ <source>Bytes:</source>
+ <translation>Байтов:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation>Количество:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation>Комиссия:</translation>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Выбрать...</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Спрятать</translation>
+ </message>
+ <message>
+ <source>Balance:</source>
+ <translation>Баланс:</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Копировать сумму</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(нет метки)</translation>
+ </message>
+</context>
<context>
<name>SendCoinsEntry</name>
</context>
<context>
<name>SendConfirmationDialog</name>
- </context>
+ <message>
+ <source>Yes</source>
+ <translation>Да</translation>
+ </message>
+</context>
<context>
<name>ShutdownWindow</name>
</context>
<context>
<name>SignVerifyMessageDialog</name>
+ <message>
+ <source>Signature</source>
+ <translation>Подпись</translation>
+ </message>
</context>
<context>
<name>SplashScreen</name>
@@ -205,9 +773,45 @@
</context>
<context>
<name>TransactionTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Метка</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(нет метки)</translation>
+ </message>
</context>
<context>
<name>TransactionView</name>
+ <message>
+ <source>Copy address</source>
+ <translation>Копировать адрес</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Копировать метку</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Копировать сумму</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Копировать ID транзакции</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Метка</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Адрес</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Экспорт не удался</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
diff --git a/src/qt/locale/bitcoin_sk.ts b/src/qt/locale/bitcoin_sk.ts
index 15a32b2050..fdf9fc6db6 100644
--- a/src/qt/locale/bitcoin_sk.ts
+++ b/src/qt/locale/bitcoin_sk.ts
@@ -41,10 +41,74 @@
<source>&amp;Delete</source>
<translation>&amp;Zmazať</translation>
</message>
- </context>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Zvoľte adresu kam poslať mince</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Zvoľte adresu na ktorú chcete prijať mince</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>Vybrať</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Odosielajúce adresy</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Prijímajúce adresy</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>Toto sú Vaše Bitcoin adresy pre posielanie platieb. Vždy skontrolujte sumu a prijímaciu adresu pred poslaním mincí.</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>Toto sú vaše Bitcoin adresy pre prijímanie platieb. Odporúča sa použiť vždy novú prijímaciu adresu pre každú transakciu.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Kopírovať adresu</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Kopírovať &amp;popis</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Upraviť</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Exportovať zoznam adries</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Čiarkou oddelovaný súbor (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Export zlyhal</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Nastala chyba pri pokuse uložiť zoznam adries do %1. Skúste znovu.</translation>
+ </message>
+</context>
<context>
<name>AddressTableModel</name>
<message>
+ <source>Label</source>
+ <translation>Popis</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adresa</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(bez popisu)</translation>
</message>
@@ -67,7 +131,95 @@
<source>Repeat new passphrase</source>
<translation>Zopakujte nové heslo</translation>
</message>
- </context>
+ <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>Zadajte nové heslo k peňaženke.&lt;br/&gt;Prosím použite heslo s dĺžkou &lt;b&gt;desať alebo viac náhodných znakov&lt;/b&gt;, prípadne &lt;b&gt;osem alebo viac slov&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Zašifrovať peňaženku</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Táto operácia potrebuje heslo k vašej peňaženke aby ju mohla odomknúť.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Odomknúť peňaženku</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Táto operácia potrebuje heslo k vašej peňaženke na dešifrovanie peňaženky.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Dešifrovať peňaženku</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Zmena hesla</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Zadajte staré heslo a nové heslo k peňaženke.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Potvrďte zašifrovanie peňaženky</translation>
+ </message>
+ <message>
+ <source>Warning: If you encrypt your wallet and lose your passphrase, you will &lt;b&gt;LOSE ALL OF YOUR BITCOINS&lt;/b&gt;!</source>
+ <translation>Varovanie: Ak zašifrujete peňaženku a stratíte heslo, &lt;b&gt;STRATÍTE VŠETKY VAŠE BITCOINY&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Ste si istí, že si želáte zašifrovať peňaženku?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Peňaženka zašifrovaná</translation>
+ </message>
+ <message>
+ <source>%1 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>%1 sa teraz zavrie, aby sa ukončil proces šifrovania. Zašifrovanie peňaženky neochráni úplne pred krádežou bitcoinov škodlivými programami, ktoré prenikli do vášho počítača.</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>DÔLEŽITÉ: Všetky predchádzajúce zálohy vašej peňaženky, ktoré ste vykonali by mali byť nahradené novo vytvorenou, zašifrovanou peňaženkou. Z bezpečnostných dôvodov bude predchádzajúca záloha nezašifrovanej peňaženky k ničomu, akonáhle začnete používať novú, zašifrovanú peňaženku.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Šifrovanie peňaženky zlyhalo</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Šifrovanie peňaženky zlyhalo kôli internej chybe. Vaša peňaženka nebola zašifrovaná.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>Zadané heslá nesúhlasia.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Odomykanie peňaženky zlyhalo</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>Zadané heslo pre dešifrovanie peňaženky bolo nesprávne.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Zlyhalo šifrovanie peňaženky.</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>Heslo k peňaženke bolo úspešne zmenené.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Upozornenie: Máte zapnutý Caps Lock!</translation>
+ </message>
+</context>
<context>
<name>BanTableModel</name>
<message>
@@ -166,6 +318,22 @@
<translation>Otvoriť &amp;URI...</translation>
</message>
<message>
+ <source>Click to disable network activity.</source>
+ <translation>Kliknite pre zakázanie sieťovej aktivity.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>Sieťová aktivita zakázaná.</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>Kliknite pre povolenie sieťovej aktivity.</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>Synchronizujú sa hlavičky (%1%)...</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>Preindexúvam bloky na disku...</translation>
</message>
@@ -277,10 +445,6 @@
<source>Processing blocks on disk...</source>
<translation>Spracovávam bloky na disku...</translation>
</message>
- <message>
- <source>No block source available...</source>
- <translation>Nedostupný zdroj blokov...</translation>
- </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation><numerusform>Spracovaných %n blok transakčnej histórie.</numerusform><numerusform>Spracovaných %n bloky transakčnej histórie.</numerusform><numerusform>Spracovaných %n blokov transakčnej histórie.</numerusform></translation>
@@ -291,7 +455,7 @@
</message>
<message>
<source>Last received block was generated %1 ago.</source>
- <translation>Posledný prijatý blok bol vygenerovaný pred %1.</translation>
+ <translation>Posledný prijatý blok bol vygenerovaný pred: %1.</translation>
</message>
<message>
<source>Transactions after this will not yet be visible.</source>
@@ -322,6 +486,10 @@
<translation>%1 klient</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>Pripája sa k partnerom...</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>Sťahujem...</translation>
</message>
@@ -364,6 +532,14 @@
<translation>Prijatá transakcia</translation>
</message>
<message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation>Generovanie HD kľúčov je &lt;b&gt;zapnuté&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation>Generovanie HD kľúčov je &lt;b&gt;vypnuté&lt;/b&gt;</translation>
+ </message>
+ <message>
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
<translation>Peňaženka je &lt;b&gt;zašifrovaná&lt;/b&gt; a momentálne &lt;b&gt;odomknutá&lt;/b&gt;</translation>
</message>
@@ -371,7 +547,11 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Peňaženka je &lt;b&gt;zašifrovaná&lt;/b&gt; a momentálne &lt;b&gt;zamknutá&lt;/b&gt;</translation>
</message>
- </context>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>Vyskytla sa kritická chyba. Bitcoin nemôže ďalej bezpečne pokračovať a ukončí sa.</translation>
+ </message>
+</context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -443,10 +623,86 @@
<translation>Potvrdené</translation>
</message>
<message>
+ <source>Copy address</source>
+ <translation>Kopírovať adresu</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopírovať popis</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopírovať sumu</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Kopírovať ID transakcie</translation>
+ </message>
+ <message>
+ <source>Lock unspent</source>
+ <translation>Uzamknúť neminuté</translation>
+ </message>
+ <message>
+ <source>Unlock unspent</source>
+ <translation>Odomknúť neminuté</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Kopírovať množstvo</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Kopírovať poplatok</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Kopírovať po poplatkoch</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Kopírovať bajty</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Kopírovať prach</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Kopírovať zmenu</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation>(%1 zamknutých)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>áno</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>nie</translation>
+ </message>
+ <message>
+ <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
+ <translation>Tento popis sčervenie ak ktorýkoľvek príjemca dostane sumu menšiu ako súčasný limit pre "prach".</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation>Môže sa líšiť o +/- %1 satoshi pre každý vstup.</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(bez popisu)</translation>
</message>
- </context>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation>zmena od %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(zmena)</translation>
+ </message>
+</context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -469,7 +725,39 @@
<source>&amp;Address</source>
<translation>&amp;Adresa</translation>
</message>
- </context>
+ <message>
+ <source>New receiving address</source>
+ <translation>Nová adresa pre prijímanie</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Nová adresa pre odoslanie</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Upraviť prijímajúcu adresu</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Upraviť odosielaciu adresu</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>Vložená adresa "%1" nieje platnou adresou Bitcoin.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book.</source>
+ <translation>Vložená adresa "%1" sa už nachádza v adresári.</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Nepodarilo sa odomknúť peňaženku.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Generovanie nového kľúča zlyhalo.</translation>
+ </message>
+</context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -598,14 +886,50 @@
<translation>Forma</translation>
</message>
<message>
+ <source>Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source>
+ <translation>Nedávne transakcie nemusia byť ešte viditeľné preto môže byť zostatok vo vašej peňaženke nesprávny. Táto informácia bude správna keď sa dokončí synchronizovanie peňaženky so sieťou bitcoin, ako je rozpísané nižšie.</translation>
+ </message>
+ <message>
+ <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source>
+ <translation>Pokus o minutie bitcoinov, ktoré sú ovplyvnené ešte nezobrazenými transakciami, nebude sieťou akceptovaný.</translation>
+ </message>
+ <message>
+ <source>Number of blocks left</source>
+ <translation>Počet zostávajúcich blokov</translation>
+ </message>
+ <message>
+ <source>Unknown...</source>
+ <translation>Neznáme...</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation>Čas posledného bloku</translation>
</message>
<message>
+ <source>Progress</source>
+ <translation>Postup synchronizácie</translation>
+ </message>
+ <message>
+ <source>Progress increase per hour</source>
+ <translation>Prírastok postupu za hodinu</translation>
+ </message>
+ <message>
+ <source>calculating...</source>
+ <translation>počíta sa...</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation>Odhadovaný čas do ukončenia synchronizácie</translation>
+ </message>
+ <message>
<source>Hide</source>
<translation>Skryť</translation>
</message>
- </context>
+ <message>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation>Neznámy. Synchronizujú sa hlavičky (%1)...</translation>
+ </message>
+</context>
<context>
<name>OpenURIDialog</name>
<message>
@@ -624,7 +948,11 @@
<source>Select payment request file</source>
<translation>Vyberte súbor s výzvou k platbe</translation>
</message>
- </context>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>Vyberte ktorý súbor s výzvou na platbu otvoriť</translation>
+ </message>
+</context>
<context>
<name>OptionsDialog</name>
<message>
@@ -937,7 +1265,91 @@
</context>
<context>
<name>PaymentServer</name>
- </context>
+ <message>
+ <source>Payment request error</source>
+ <translation>Chyba pri vyžiadaní platby</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation>URI manipulácia</translation>
+ </message>
+ <message>
+ <source>Payment request fetch URL is invalid: %1</source>
+ <translation>URL pre stiahnutie výzvy na zaplatenie je neplatné: %1</translation>
+ </message>
+ <message>
+ <source>Invalid payment address %1</source>
+ <translation>Neplatná adresa platby %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 sa nedá analyzovať! To môže byť spôsobené neplatnou Bitcoin adresou alebo zle nastavenými vlastnosťami URI.</translation>
+ </message>
+ <message>
+ <source>Payment request file handling</source>
+ <translation>Obsluha súboru s požiadavkou na platbu</translation>
+ </message>
+ <message>
+ <source>Payment request file cannot be read! This can be caused by an invalid payment request file.</source>
+ <translation>Súbor s výzvou na zaplatenie sa nedá čítať! To môže byť spôsobené aj neplatným súborom s výzvou.</translation>
+ </message>
+ <message>
+ <source>Payment request rejected</source>
+ <translation>Požiadavka na platbu zamietnutá</translation>
+ </message>
+ <message>
+ <source>Payment request network doesn't match client network.</source>
+ <translation>Sieť požiadavky na platbu nie je zhodná so sieťou klienta.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Vypršala platnosť požiadavky na platbu.</translation>
+ </message>
+ <message>
+ <source>Payment request is not initialized.</source>
+ <translation>Požiadavka na platbu nie je inicializovaná</translation>
+ </message>
+ <message>
+ <source>Unverified payment requests to custom payment scripts are unsupported.</source>
+ <translation>Program nepodporuje neoverené platobné požiadavky na vlastné skripty.</translation>
+ </message>
+ <message>
+ <source>Invalid payment request.</source>
+ <translation>Chybná požiadavka na platbu.</translation>
+ </message>
+ <message>
+ <source>Requested payment amount of %1 is too small (considered dust).</source>
+ <translation>Požadovaná suma platby %1 je príliš nízka (považovaná za prach).</translation>
+ </message>
+ <message>
+ <source>Refund from %1</source>
+ <translation>Vrátenie z %1</translation>
+ </message>
+ <message>
+ <source>Payment request %1 is too large (%2 bytes, allowed %3 bytes).</source>
+ <translation>Požiadavka na platbu %1 je príliš veľká (%2 bajtov, povolené je %3 bajtov).</translation>
+ </message>
+ <message>
+ <source>Error communicating with %1: %2</source>
+ <translation>Chyba komunikácie s %1: %2 </translation>
+ </message>
+ <message>
+ <source>Payment request cannot be parsed!</source>
+ <translation>Požiadavka na platbu nemôže byť analyzovaná!</translation>
+ </message>
+ <message>
+ <source>Bad response from server %1</source>
+ <translation>Zlá odpoveď zo servera %1</translation>
+ </message>
+ <message>
+ <source>Network request error</source>
+ <translation>Chyba požiadavky siete</translation>
+ </message>
+ <message>
+ <source>Payment acknowledged</source>
+ <translation>Platba potvrdená</translation>
+ </message>
+</context>
<context>
<name>PeerTableModel</name>
<message>
@@ -948,7 +1360,15 @@
<source>Node/Service</source>
<translation>Uzol/Služba</translation>
</message>
- </context>
+ <message>
+ <source>NodeId</source>
+ <translation>ID uzlu</translation>
+ </message>
+ <message>
+ <source>Ping</source>
+ <translation>Odozva</translation>
+ </message>
+</context>
<context>
<name>QObject</name>
<message>
@@ -987,17 +1407,65 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation><numerusform>%n sekunda</numerusform><numerusform>%n sekundy</numerusform><numerusform>%n sekúnd</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation><numerusform>%n minúta</numerusform><numerusform>%n minúty</numerusform><numerusform>%n minút</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation><numerusform>%n hodina</numerusform><numerusform>%n hodiny</numerusform><numerusform>%n hodín</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation><numerusform>%n deň</numerusform><numerusform>%n dni</numerusform><numerusform>%n dní</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation><numerusform>%n týždeň</numerusform><numerusform>%n týždne</numerusform><numerusform>%n týždňov</numerusform></translation>
+ </message>
<message>
<source>%1 and %2</source>
<translation> %1 a %2</translation>
</message>
- </context>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation><numerusform>%n rok</numerusform><numerusform>%n roky</numerusform><numerusform>%n rokov</numerusform></translation>
+ </message>
+ <message>
+ <source>%1 didn't yet exit safely...</source>
+ <translation>%1 ešte nebol bezpečne ukončený...</translation>
+ </message>
+</context>
<context>
<name>QObject::QObject</name>
- </context>
+ <message>
+ <source>Error: %1</source>
+ <translation>Chyba: %1</translation>
+ </message>
+</context>
<context>
<name>QRImageWidget</name>
- </context>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>Uložiť obrázok...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>Kopírovať obrázok</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>Uložiť QR Code</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>PNG obrázok (*.png)</translation>
+ </message>
+</context>
<context>
<name>RPCConsole</name>
<message>
@@ -1022,11 +1490,11 @@
</message>
<message>
<source>Using BerkeleyDB version</source>
- <translation>Používa BerkeleyDB verziu</translation>
+ <translation>Používa verziu BerkeleyDB</translation>
</message>
<message>
<source>Datadir</source>
- <translation>Zložka s dátami</translation>
+ <translation>Priečinok s dátami</translation>
</message>
<message>
<source>Startup time</source>
@@ -1058,7 +1526,7 @@
</message>
<message>
<source>Current number of transactions</source>
- <translation>Aktuálny počet tranzakcií</translation>
+ <translation>Aktuálny počet transakcií</translation>
</message>
<message>
<source>Memory usage</source>
@@ -1098,7 +1566,7 @@
</message>
<message>
<source>Starting Block</source>
- <translation>Počiatočný Blok</translation>
+ <translation>Počiatočný blok</translation>
</message>
<message>
<source>Synced Headers</source>
@@ -1151,11 +1619,15 @@
</message>
<message>
<source>The duration of a currently outstanding ping.</source>
- <translation>Trvanie aktuálneho pingu</translation>
+ <translation>Trvanie aktuálnej požiadavky na odozvu.</translation>
</message>
<message>
<source>Ping Wait</source>
- <translation>Čakanie na ping</translation>
+ <translation>Čakanie na odozvu</translation>
+ </message>
+ <message>
+ <source>Min Ping</source>
+ <translation>Minimálna odozva</translation>
</message>
<message>
<source>Time Offset</source>
@@ -1218,6 +1690,18 @@
<translation>1 &amp;rok</translation>
</message>
<message>
+ <source>&amp;Disconnect</source>
+ <translation>&amp;Odpojiť</translation>
+ </message>
+ <message>
+ <source>Ban for</source>
+ <translation>Zakázať na</translation>
+ </message>
+ <message>
+ <source>&amp;Unban</source>
+ <translation>&amp;Zrušiť zákaz</translation>
+ </message>
+ <message>
<source>Welcome to the %1 RPC console.</source>
<translation>Vitajte v %1 RPC konzole</translation>
</message>
@@ -1230,6 +1714,14 @@
<translation>Napíš &lt;b&gt;help&lt;/b&gt; pre prehľad dostupných príkazov.</translation>
</message>
<message>
+ <source>WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramification of a command.</source>
+ <translation>VAROVANIE: Podvodníci sú aktívni a môžu nabádať používateľov napísať sem príkazy, pomocou ktorých ukradnú ich obsah peňaženky. Nepoužívajte túto konzolu ak nerozumiete presne účinkom príkazov.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled</source>
+ <translation>Sieťová aktivita zakázaná</translation>
+ </message>
+ <message>
<source>%1 B</source>
<translation>%1 B</translation>
</message>
@@ -1348,7 +1840,23 @@
<source>Remove</source>
<translation>Odstrániť</translation>
</message>
- </context>
+ <message>
+ <source>Copy URI</source>
+ <translation>Kopírovať URI</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopírovať popis</translation>
+ </message>
+ <message>
+ <source>Copy message</source>
+ <translation>Kopírovať správu</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopírovať sumu</translation>
+ </message>
+</context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -1367,14 +1875,74 @@
<source>&amp;Save Image...</source>
<translation>Uložiť obrázok...</translation>
</message>
- </context>
+ <message>
+ <source>Request payment to %1</source>
+ <translation>Vyžiadať platbu pre %1</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>Informácia o platbe</translation>
+ </message>
+ <message>
+ <source>URI</source>
+ <translation>URI</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adresa</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Suma</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Popis</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Správa</translation>
+ </message>
+ <message>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation>Výsledné URI je príliš dlhé, skúste skrátiť text pre popis alebo správu.</translation>
+ </message>
+ <message>
+ <source>Error encoding URI into QR Code.</source>
+ <translation>Chyba kódovania URI do QR Code.</translation>
+ </message>
+</context>
<context>
<name>RecentRequestsTableModel</name>
<message>
+ <source>Date</source>
+ <translation>Dátum</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Popis</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Správa</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(bez popisu)</translation>
</message>
- </context>
+ <message>
+ <source>(no message)</source>
+ <translation>(žiadna správa)</translation>
+ </message>
+ <message>
+ <source>(no amount requested)</source>
+ <translation>(nepožadovaná žiadna suma)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation>Požadované</translation>
+ </message>
+</context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1475,7 +2043,7 @@
</message>
<message>
<source>(Smart fee not initialized yet. This usually takes a few blocks...)</source>
- <translation>(Automatický poplatok ešte nebol aktivovaný. Toto zvyčajne trvá niekoľko blokov...)</translation>
+ <translation>(Automatický poplatok ešte nebol vypočítaný. Toto zvyčajne trvá niekoľko blokov...)</translation>
</message>
<message>
<source>normal</source>
@@ -1502,6 +2070,10 @@
<translation>Prach:</translation>
</message>
<message>
+ <source>Confirmation time target:</source>
+ <translation>Cieľový čas potvrdenia:</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>&amp;Zmazať všetko</translation>
</message>
@@ -1518,10 +2090,122 @@
<translation>&amp;Odoslať</translation>
</message>
<message>
+ <source>Copy quantity</source>
+ <translation>Kopírovať množstvo</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopírovať sumu</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Kopírovať poplatok</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Kopírovať po poplatkoch</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Kopírovať bajty</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Kopírovať prach</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Kopírovať zmenu</translation>
+ </message>
+ <message>
+ <source>%1 to %2</source>
+ <translation>%1 do %2</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to send?</source>
+ <translation>Určite chcete odoslať transakciu?</translation>
+ </message>
+ <message>
+ <source>added as transaction fee</source>
+ <translation>pridané ako poplatok za transakciu</translation>
+ </message>
+ <message>
+ <source>Total Amount %1</source>
+ <translation>Celková suma %1</translation>
+ </message>
+ <message>
<source>or</source>
<translation>alebo</translation>
</message>
<message>
+ <source>Confirm send coins</source>
+ <translation>Potvrďte odoslanie mincí</translation>
+ </message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>Adresa príjemcu je neplatná. Prosím, overte ju.</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation>Suma na úhradu musí byť väčšia ako 0.</translation>
+ </message>
+ <message>
+ <source>The amount exceeds your balance.</source>
+ <translation>Suma je vyššia ako Váš zostatok.</translation>
+ </message>
+ <message>
+ <source>The total exceeds your balance when the %1 transaction fee is included.</source>
+ <translation>Celková suma prevyšuje Váš zostatok ak sú započítané aj transakčné poplatky %1.</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation>Našla sa duplicitná adresa: každá adresa by sa mala použiť len raz.</translation>
+ </message>
+ <message>
+ <source>Transaction creation failed!</source>
+ <translation>Vytvorenie transakcie zlyhalo!</translation>
+ </message>
+ <message>
+ <source>The transaction was rejected with the following reason: %1</source>
+ <translation>Transakcia bola odmietnutá z nasledujúceho dôvodu: %1</translation>
+ </message>
+ <message>
+ <source>A fee higher than %1 is considered an absurdly high fee.</source>
+ <translation>Poplatok vyšší ako %1 sa považuje za neprimerane vysoký.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Vypršala platnosť požiadavky na platbu.</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n block(s)</source>
+ <translation><numerusform>%n blok</numerusform><numerusform>%n bloky</numerusform><numerusform>%n blokov</numerusform></translation>
+ </message>
+ <message>
+ <source>Pay only the required fee of %1</source>
+ <translation>Zaplatiť iba požadovaný poplatok %1</translation>
+ </message>
+ <message numerus="yes">
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation><numerusform>Odhadovaný začiatok potvrdzovania po %n bloku.</numerusform><numerusform>Odhadovaný začiatok potvrdzovania po %n blokoch.</numerusform><numerusform>Odhadovaný začiatok potvrdzovania po %n blokoch.</numerusform></translation>
+ </message>
+ <message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>Varovanie: Neplatná Bitcoin adresa</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <translation>UPOZORNENIE: Neznáma zmena adresy</translation>
+ </message>
+ <message>
+ <source>Confirm custom change address</source>
+ <translation>Potvrďte zmenu adresy</translation>
+ </message>
+ <message>
+ <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source>
+ <translation>Zadaná adresa nie je súčasťou tejto peňaženky. Časť alebo všetky peniaze z peňaženky môžu byť odoslané na túto adresu. Ste si istý?</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(bez popisu)</translation>
</message>
@@ -1558,7 +2242,7 @@
</message>
<message>
<source>Paste address from clipboard</source>
- <translation>Vložte adresu z klipbordu</translation>
+ <translation>Vložiť adresu zo schránky</translation>
</message>
<message>
<source>Alt+P</source>
@@ -1604,10 +2288,18 @@
<source>Memo:</source>
<translation>Poznámka:</translation>
</message>
- </context>
+ <message>
+ <source>Enter a label for this address to add it to your address book</source>
+ <translation>Zadajte popis pre túto adresu pre pridanie do adresára</translation>
+ </message>
+</context>
<context>
<name>SendConfirmationDialog</name>
- </context>
+ <message>
+ <source>Yes</source>
+ <translation>áno</translation>
+ </message>
+</context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1630,6 +2322,10 @@
<translation>&amp;Podpísať Správu</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>Môžete podpísať správy svojou adresou a dokázať, že viete prijímať mince zaslané na túto adresu. Buďte však opatrní a podpíšte len podrobné prehlásenia, s ktorými plne súhlasíte, nakoľko útoky typu "phishing" Vás môžu lákať k podpísaniu nejasných alebo príliš všeobecných tvrdení čím prevezmú vašu identitu.</translation>
+ </message>
+ <message>
<source>The Bitcoin address to sign the message with</source>
<translation>Bitcoin adresa pre podpísanie správy s</translation>
</message>
@@ -1643,7 +2339,7 @@
</message>
<message>
<source>Paste address from clipboard</source>
- <translation>Vložte adresu z klipbordu</translation>
+ <translation>Vložiť adresu zo schránky</translation>
</message>
<message>
<source>Alt+P</source>
@@ -1659,7 +2355,7 @@
</message>
<message>
<source>Copy the current signature to the system clipboard</source>
- <translation>Kopírovať práve zvolenú adresu do systémového klipbordu</translation>
+ <translation>Kopírovať tento podpis do systémovej schránky</translation>
</message>
<message>
<source>Sign the message to prove you own this Bitcoin address</source>
@@ -1682,6 +2378,10 @@
<translation>O&amp;veriť správu...</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>Vložte adresu príjemcu, správu (uistite sa, že presne kopírujete ukončenia riadkov, medzery, odrážky, atď.) a podpis pre potvrdenie správy. Buďte opatrní a nedomýšľajte si viac než je uvedené v samotnej podpísanej správe a môžete sa tak vyhnúť podvodu MITM útokom. Toto len potvrdzuje, že podpisujúca strana môže prijímať na tejto adrese, nepotvrdzuje to vlastníctvo žiadnej transakcie!</translation>
+ </message>
+ <message>
<source>The Bitcoin address the message was signed with</source>
<translation>Adresa Bitcoin, ktorou bola podpísaná správa</translation>
</message>
@@ -1697,7 +2397,59 @@
<source>Reset all verify message fields</source>
<translation>Obnoviť všetky polia v overiť správu</translation>
</message>
- </context>
+ <message>
+ <source>Click "Sign Message" to generate signature</source>
+ <translation>Kliknite "Podpísať správu" pre vytvorenie podpisu</translation>
+ </message>
+ <message>
+ <source>The entered address is invalid.</source>
+ <translation>Zadaná adresa je neplatná.</translation>
+ </message>
+ <message>
+ <source>Please check the address and try again.</source>
+ <translation>Prosím skontrolujte adresu a skúste znova.</translation>
+ </message>
+ <message>
+ <source>The entered address does not refer to a key.</source>
+ <translation>Vložená adresa nezodpovedá žiadnemu kľúču.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock was cancelled.</source>
+ <translation>Odomknutie peňaženky bolo zrušené.</translation>
+ </message>
+ <message>
+ <source>Private key for the entered address is not available.</source>
+ <translation>Súkromný kľúč pre zadanú adresu nieje k dispozícii.</translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation>Podpísanie správy zlyhalo.</translation>
+ </message>
+ <message>
+ <source>Message signed.</source>
+ <translation>Správa podpísaná.</translation>
+ </message>
+ <message>
+ <source>The signature could not be decoded.</source>
+ <translation>Podpis nie je možné dekódovať.</translation>
+ </message>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation>Prosím skontrolujte podpis a skúste znova.</translation>
+ </message>
+ <message>
+ <source>The signature did not match the message digest.</source>
+ <translation>Podpis sa nezhoduje so zhrnutím správy.</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation>Overenie správy zlyhalo.</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation>Správa overená.</translation>
+ </message>
+</context>
<context>
<name>SplashScreen</name>
<message>
@@ -1714,24 +2466,416 @@
</context>
<context>
<name>TransactionDesc</name>
- </context>
+ <message>
+ <source>Open until %1</source>
+ <translation>Otvorené do %1</translation>
+ </message>
+ <message>
+ <source>conflicted with a transaction with %1 confirmations</source>
+ <translation>koliduje s transakciou s %1 potvrdeniami</translation>
+ </message>
+ <message>
+ <source>%1/offline</source>
+ <translation>%1/offline</translation>
+ </message>
+ <message>
+ <source>0/unconfirmed, %1</source>
+ <translation>0/nepotvrdené, %1</translation>
+ </message>
+ <message>
+ <source>%1/unconfirmed</source>
+ <translation>%1/nepotvrdené</translation>
+ </message>
+ <message>
+ <source>%1 confirmations</source>
+ <translation>%1 potvrdení</translation>
+ </message>
+ <message>
+ <source>Status</source>
+ <translation>Stav</translation>
+ </message>
+ <message>
+ <source>, has not been successfully broadcast yet</source>
+ <translation>, ešte nebola úspešne odoslaná</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Dátum</translation>
+ </message>
+ <message>
+ <source>Source</source>
+ <translation>Zdroj</translation>
+ </message>
+ <message>
+ <source>Generated</source>
+ <translation>Vygenerované</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>Od</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>neznámy</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation>do</translation>
+ </message>
+ <message>
+ <source>own address</source>
+ <translation>vlastná adresa</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>Iba sledovanie</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>popis</translation>
+ </message>
+ <message>
+ <source>Credit</source>
+ <translation>Kredit</translation>
+ </message>
+ <message>
+ <source>not accepted</source>
+ <translation>neprijaté</translation>
+ </message>
+ <message>
+ <source>Debit</source>
+ <translation>Debet</translation>
+ </message>
+ <message>
+ <source>Total debit</source>
+ <translation>Celkový debet</translation>
+ </message>
+ <message>
+ <source>Total credit</source>
+ <translation>Celkový kredit</translation>
+ </message>
+ <message>
+ <source>Transaction fee</source>
+ <translation>Transakčný poplatok</translation>
+ </message>
+ <message>
+ <source>Net amount</source>
+ <translation>Suma netto</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Správa</translation>
+ </message>
+ <message>
+ <source>Comment</source>
+ <translation>Komentár</translation>
+ </message>
+ <message>
+ <source>Transaction ID</source>
+ <translation>ID transakcie</translation>
+ </message>
+ <message>
+ <source>Transaction total size</source>
+ <translation>Celková veľkosť transakcie</translation>
+ </message>
+ <message>
+ <source>Merchant</source>
+ <translation>Kupec</translation>
+ </message>
+ <message>
+ <source>Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source>
+ <translation>Vytvorené coins musia dospieť %1 blokov kým môžu byť minuté. Keď vytvoríte tento blok, bude rozoslaný do siete aby bol akceptovaný do reťaze blokov. Ak sa nedostane reťaze, jeho stav sa zmení na "zamietnutý" a nebude sa dať minúť. Toto sa môže občas stať ak iná nóda vytvorí blok približne v tom istom čase.</translation>
+ </message>
+ <message>
+ <source>Debug information</source>
+ <translation>Ladiace informácie</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation>Transakcie</translation>
+ </message>
+ <message>
+ <source>Inputs</source>
+ <translation>Vstupy</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Suma</translation>
+ </message>
+ <message>
+ <source>true</source>
+ <translation>pravda</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation>nepravda</translation>
+ </message>
+</context>
<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Táto časť obrazovky zobrazuje detailný popis transakcie</translation>
</message>
- </context>
+ <message>
+ <source>Details for %1</source>
+ <translation>Podrobnosti pre %1</translation>
+ </message>
+</context>
<context>
<name>TransactionTableModel</name>
<message>
+ <source>Date</source>
+ <translation>Dátum</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Typ</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Popis</translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>Otvorené do %1</translation>
+ </message>
+ <message>
+ <source>Offline</source>
+ <translation>Offline</translation>
+ </message>
+ <message>
+ <source>Unconfirmed</source>
+ <translation>Nepotvrdené</translation>
+ </message>
+ <message>
+ <source>Confirming (%1 of %2 recommended confirmations)</source>
+ <translation>Potvrdzujem (%1 z %2 odporúčaných potvrdení)</translation>
+ </message>
+ <message>
+ <source>Confirmed (%1 confirmations)</source>
+ <translation>Potvrdené (%1 potvrdení)</translation>
+ </message>
+ <message>
+ <source>Conflicted</source>
+ <translation>V rozpore</translation>
+ </message>
+ <message>
+ <source>Immature (%1 confirmations, will be available after %2)</source>
+ <translation>Nezrelé (%1 potvrdení, bude dostupné po %2)</translation>
+ </message>
+ <message>
+ <source>This block was not received by any other nodes and will probably not be accepted!</source>
+ <translation>Ten blok nebol prijatý žiadnym iným uzlom a pravdepodobne nebude akceptovaný!</translation>
+ </message>
+ <message>
+ <source>Generated but not accepted</source>
+ <translation>Vypočítané ale neakceptované</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Prijaté s</translation>
+ </message>
+ <message>
+ <source>Received from</source>
+ <translation>Prijaté od</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Odoslané na</translation>
+ </message>
+ <message>
+ <source>Payment to yourself</source>
+ <translation>Platba sebe samému</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Vyťažené</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>Iba sledovanie</translation>
+ </message>
+ <message>
+ <source>(n/a)</source>
+ <translation>(n/a)</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(bez popisu)</translation>
</message>
- </context>
+ <message>
+ <source>Transaction status. Hover over this field to show number of confirmations.</source>
+ <translation>Stav transakcie. Prejdite ponad toto pole pre zobrazenie počtu potvrdení.</translation>
+ </message>
+ <message>
+ <source>Date and time that the transaction was received.</source>
+ <translation>Dátum a čas prijatia transakcie.</translation>
+ </message>
+ <message>
+ <source>Type of transaction.</source>
+ <translation>Typ transakcie.</translation>
+ </message>
+ <message>
+ <source>Whether or not a watch-only address is involved in this transaction.</source>
+ <translation>Či je v tejto transakcii adresy iba na sledovanie.</translation>
+ </message>
+ <message>
+ <source>Amount removed from or added to balance.</source>
+ <translation>Suma pridaná alebo odobraná k zostatku.</translation>
+ </message>
+</context>
<context>
<name>TransactionView</name>
- </context>
+ <message>
+ <source>All</source>
+ <translation>Všetky</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>Dnes</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>Tento týždeň</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>Tento mesiac</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>Minulý mesiac</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>Tento rok</translation>
+ </message>
+ <message>
+ <source>Range...</source>
+ <translation>Rozsah...</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Prijaté s</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Odoslané na</translation>
+ </message>
+ <message>
+ <source>To yourself</source>
+ <translation>Ku mne</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Vyťažené</translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation>Iné</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation>Zadajte adresu alebo popis pre hľadanie</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation>Minimálna suma</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Kopírovať adresu</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopírovať popis</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopírovať sumu</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Kopírovať ID transakcie</translation>
+ </message>
+ <message>
+ <source>Copy raw transaction</source>
+ <translation>Skopírovať neupravenú transakciu</translation>
+ </message>
+ <message>
+ <source>Copy full transaction details</source>
+ <translation>Kopírovať všetky podrobnosti o transakcii</translation>
+ </message>
+ <message>
+ <source>Edit label</source>
+ <translation>Upraviť popis</translation>
+ </message>
+ <message>
+ <source>Show transaction details</source>
+ <translation>Zobraziť podrobnosti transakcie</translation>
+ </message>
+ <message>
+ <source>Export Transaction History</source>
+ <translation>Exportovať históriu transakcií</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Čiarkou oddelovaný súbor (*.csv)</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation>Potvrdené</translation>
+ </message>
+ <message>
+ <source>Watch-only</source>
+ <translation>Iba sledovanie</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Dátum</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Typ</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Popis</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adresa</translation>
+ </message>
+ <message>
+ <source>ID</source>
+ <translation>ID</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Export zlyhal</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the transaction history to %1.</source>
+ <translation>Vyskytla sa chyba pri pokuse o uloženie histórie transakcií do %1.</translation>
+ </message>
+ <message>
+ <source>Exporting Successful</source>
+ <translation>Export úspešný</translation>
+ </message>
+ <message>
+ <source>The transaction history was successfully saved to %1.</source>
+ <translation>História transakciá bola úspešne uložená do %1.</translation>
+ </message>
+ <message>
+ <source>Range:</source>
+ <translation>Rozsah:</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>do</translation>
+ </message>
+</context>
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
@@ -1741,13 +2885,53 @@
</context>
<context>
<name>WalletFrame</name>
- </context>
+ <message>
+ <source>No wallet has been loaded.</source>
+ <translation>Nie je načítaná peňaženka.</translation>
+ </message>
+</context>
<context>
<name>WalletModel</name>
- </context>
+ <message>
+ <source>Send Coins</source>
+ <translation>Poslať mince</translation>
+ </message>
+</context>
<context>
<name>WalletView</name>
- </context>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;Exportovať...</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Exportovať dáta v aktuálnej karte do súboru</translation>
+ </message>
+ <message>
+ <source>Backup Wallet</source>
+ <translation>Zálohovanie peňaženky</translation>
+ </message>
+ <message>
+ <source>Wallet Data (*.dat)</source>
+ <translation>Dáta peňaženky (*.dat)</translation>
+ </message>
+ <message>
+ <source>Backup Failed</source>
+ <translation>Zálohovanie zlyhalo</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the wallet data to %1.</source>
+ <translation>Vyskytla sa chyba pri pokuse o uloženie dát peňaženky do %1.</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation>Záloha úspešná</translation>
+ </message>
+ <message>
+ <source>The wallet data was successfully saved to %1.</source>
+ <translation>Dáta peňaženky boli úspešne uložené do %1.</translation>
+ </message>
+</context>
<context>
<name>bitcoin-core</name>
<message>
@@ -1771,6 +2955,10 @@
<translation>Prijímať príkazy z príkazového riadku a JSON-RPC</translation>
</message>
<message>
+ <source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
+ <translation>Distribuované pod softvérovou licenciou MIT, viď sprievodný súbor %s alebo %s</translation>
+ </message>
+ <message>
<source>If &lt;category&gt; is not supplied or if &lt;category&gt; = 1, output all debugging information.</source>
<translation>Pokiaľ &lt;category&gt; nie je nastavená, alebo &lt;category&gt; = 1, vypíš všetky informácie pre ladenie.</translation>
</message>
@@ -1784,7 +2972,7 @@
</message>
<message>
<source>Fee (in %s/kB) to add to transactions you send (default: %s)</source>
- <translation>Poplatok (za %s/kB) pridaný do tranzakcie, ktorú posielate (predvolené: %s)</translation>
+ <translation>Poplatok (za %s/kB) pridaný do transakcie, ktorú posielate (predvolené: %s)</translation>
</message>
<message>
<source>Pruning blockstore...</source>
@@ -1800,13 +2988,17 @@
</message>
<message>
<source>Bitcoin Core</source>
- <translation>Jadro Bitcoin</translation>
+ <translation>Bitcoin Core</translation>
</message>
<message>
<source>The %s developers</source>
<translation>Vývojári %s</translation>
</message>
<message>
+ <source>Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)</source>
+ <translation>Akceptovať postúpené transakcie od povolených partnerov aj keď normálne nepostupujete transakcie (predvolené: %d)</translation>
+ </message>
+ <message>
<source>Bind to given address and always listen on it. Use [host]:port notation for IPv6</source>
<translation>Spojiť s danou adresou a vždy na nej počúvať. Použite zápis [host]:port pre IPv6</translation>
</message>
@@ -1843,6 +3035,26 @@
<translation>Databáza blokov obsahuje blok, ktorý vyzerá byť z budúcnosti. Toto môže byť spôsobené nesprávnym systémovým časom vášho počítača. Obnovujte databázu blokov len keď ste si istý, že systémový čas je nastavený správne.</translation>
</message>
<message>
+ <source>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source>
+ <translation>Toto je predbežná testovacia zostava - používate na vlastné riziko - nepoužívajte na ťaženie alebo obchodné aplikácie</translation>
+ </message>
+ <message>
+ <source>Use UPnP to map the listening port (default: 1 when listening and no -proxy)</source>
+ <translation>Skúsiť použiť UPnP pre mapovanie počúvajúceho portu (predvolené: 1 počas počúvania a bez -proxy)</translation>
+ </message>
+ <message>
+ <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
+ <translation>Varovanie: Javí sa že sieť sieť úplne nesúhlasí! Niektorí mineri zjavne majú ťažkosti.</translation>
+ </message>
+ <message>
+ <source>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source>
+ <translation>Varovanie: Zjavne sa úplne nezhodujeme s našimi peer-mi! Možno potrebujete prejsť na novšiu verziu alebo ostatné uzly potrebujú vyššiu verziu.</translation>
+ </message>
+ <message>
+ <source>You need to rebuild the database using -reindex-chainstate to change -txindex</source>
+ <translation>Potrebujete prebudovať databázu použitím -reindex-chainstate pre zmenu -txindex</translation>
+ </message>
+ <message>
<source>%s corrupt, salvage failed</source>
<translation>%s je poškodený, záchrana zlyhala</translation>
</message>
@@ -1855,6 +3067,10 @@
<translation>&lt;category&gt; môže byť:</translation>
</message>
<message>
+ <source>Attempt to recover private keys from a corrupt wallet on startup</source>
+ <translation>Pokúsiť sa o obnovenie privátnych kľúčov z poškodenej peňaženky pri spustení</translation>
+ </message>
+ <message>
<source>Block creation options:</source>
<translation>Voľby vytvorenia bloku:</translation>
</message>
@@ -1892,7 +3108,7 @@
</message>
<message>
<source>Enable publish hash transaction in &lt;address&gt;</source>
- <translation>Povoliť zverejnenie hash tranzakcií pre &lt;address&gt;</translation>
+ <translation>Povoliť zverejnenie hash transakcií pre &lt;address&gt;</translation>
</message>
<message>
<source>Enable publish raw block in &lt;address&gt;</source>
@@ -1968,7 +3184,7 @@
</message>
<message>
<source>Location of the auth cookie (default: data dir)</source>
- <translation>Poloha overovacieho cookie súboru (predvolená: zložka s dátami)</translation>
+ <translation>Umiestnenie overovacieho cookie súboru (predvolená: Priečinok s dátami)</translation>
</message>
<message>
<source>Not enough file descriptors available.</source>
@@ -2039,6 +3255,10 @@
<translation>Použiť UPnP pre mapovanie počúvajúceho portu (predvolené: %u)</translation>
</message>
<message>
+ <source>Use the test chain</source>
+ <translation>Použiť testovaciu sieť</translation>
+ </message>
+ <message>
<source>Verifying blocks...</source>
<translation>Overujem bloky...</translation>
</message>
@@ -2091,6 +3311,10 @@
<translation>Vykonať príkaz po prijatí patričného varovania alebo uvidíme veľmi dlhé rozdvojenie siete (%s v cmd je nahradené správou)</translation>
</message>
<message>
+ <source>Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)</source>
+ <translation>Poplatky (v %s/kB) menšie ako toto, sú považované za nulový transakčný poplatok (predvolené: %s)</translation>
+ </message>
+ <message>
<source>If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)</source>
<translation>Ak nie je nastavené paytxfee, pridať dostatočný poplatok aby sa transakcia začala potvrdzovať priemerne v rámci bloku (predvolené: %u)</translation>
</message>
@@ -2108,7 +3332,7 @@
</message>
<message>
<source>The transaction amount is too small to send after the fee has been deducted</source>
- <translation>Suma je príliš malá pre odoslanie tranzakcie</translation>
+ <translation>Suma je príliš malá pre odoslanie transakcie</translation>
</message>
<message>
<source>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</source>
@@ -2192,7 +3416,7 @@
</message>
<message>
<source>The transaction amount is too small to pay the fee</source>
- <translation>Suma tranzakcie je príliš malá na zaplatenie poplatku</translation>
+ <translation>Suma transakcie je príliš malá na zaplatenie poplatku</translation>
</message>
<message>
<source>This is experimental software.</source>
@@ -2259,6 +3483,10 @@
<translation>(1 = zachovať metaúdaje tx napr. vlastníka účtu a informácie o platobných príkazoch, 2 = zahodiť metaúdaje tx)</translation>
</message>
<message>
+ <source>Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)</source>
+ <translation>Poplatky (v %s/kB) menšie ako toto, sú považované za nulový transakčný poplatok (predvolené: %s)</translation>
+ </message>
+ <message>
<source>How thorough the block verification of -checkblocks is (0-4, default: %u)</source>
<translation>Ako dôkladné je -checkblocks overenie blokov (0-4, predvolené: %u)</translation>
</message>
@@ -2275,6 +3503,10 @@
<translation>Výstupné ladiace informácie (predvolené: %u, dodanie &lt;category&gt; je voliteľné)</translation>
</message>
<message>
+ <source>This is the transaction fee you may pay when fee estimates are not available.</source>
+ <translation>Toto je poplatok za transakciu keď odhad poplatkov ešte nie je k dispozícii.</translation>
+ </message>
+ <message>
<source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source>
<translation>Celková dĺžka verzie sieťového reťazca (%i) prekračuje maximálnu dĺžku (%i). Znížte počet a veľkosť komentárov.</translation>
</message>
@@ -2303,6 +3535,14 @@
<translation>Varovanie: Peňaženka poškodená, dáta boli zachránené! Originálna %s ako %s v %s; ak váš zostatok alebo transakcie sú nesprávne, mali by ste obnoviť zálohu.</translation>
</message>
<message>
+ <source>Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR notated network (e.g. 1.2.3.0/24). Can be specified multiple times.</source>
+ <translation>Povoliť partnerov pripájajúcich sa z danej IP adresy (napr. 1.2.3.4) alebo zo siete vo formáte CIDR (napr. 1.2.3.0/24). Môže byť zadané viackrát.</translation>
+ </message>
+ <message>
+ <source>%s is set very high!</source>
+ <translation>Hodnota %s je nastavená veľmi vysoko!</translation>
+ </message>
+ <message>
<source>(default: %s)</source>
<translation>(predvolené: %s)</translation>
</message>
@@ -2379,10 +3619,34 @@
<translation>Minúť nepotvrdené zmenu pri posielaní transakcií (predvolené: %u)</translation>
</message>
<message>
+ <source>Starting network threads...</source>
+ <translation>Spúšťajú sa sieťové vlákna...</translation>
+ </message>
+ <message>
+ <source>The wallet will avoid paying less than the minimum relay fee.</source>
+ <translation>Peňaženka zabráni zaplateniu menšej sumy ako je minimálny poplatok.</translation>
+ </message>
+ <message>
+ <source>This is the minimum transaction fee you pay on every transaction.</source>
+ <translation>Toto je minimálny poplatok za transakciu pri každej transakcii.</translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you will pay if you send a transaction.</source>
+ <translation>Toto je poplatok za transakciu pri odoslaní transakcie.</translation>
+ </message>
+ <message>
<source>Threshold for disconnecting misbehaving peers (default: %u)</source>
<translation>Hranica pre odpájanie zle sa správajúcim partnerským uzlom (predvolené: %u)</translation>
</message>
<message>
+ <source>Transaction amounts must not be negative</source>
+ <translation>Sumy transakcií nesmú byť záporné</translation>
+ </message>
+ <message>
+ <source>Transaction must have at least one recipient</source>
+ <translation>Transakcia musí mať aspoň jedného príjemcu</translation>
+ </message>
+ <message>
<source>Unknown network specified in -onlynet: '%s'</source>
<translation>Neznáma sieť upresnená v -onlynet: '%s'</translation>
</message>
diff --git a/src/qt/locale/bitcoin_sl_SI.ts b/src/qt/locale/bitcoin_sl_SI.ts
index 1c8cb4ce56..ae10378bf2 100644
--- a/src/qt/locale/bitcoin_sl_SI.ts
+++ b/src/qt/locale/bitcoin_sl_SI.ts
@@ -41,10 +41,50 @@
<source>&amp;Delete</source>
<translation>I&amp;zbriši</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Izberi naslov prejemnika kovancev</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Izberi naslov, na katerega želiš prejeti kovance</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>&amp;Izberi</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Imenik naslovov za pošiljanje</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Imenik naslovov za prejemanje</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Izvozi seznam naslovov</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Podatkov ni bilo mogoče izvoziti.</translation>
+ </message>
</context>
<context>
<name>AddressTableModel</name>
- </context>
+ <message>
+ <source>Label</source>
+ <translation>Oznaka</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Naslov</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(brez oznake)</translation>
+ </message>
+</context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -63,6 +103,14 @@
<source>Repeat new passphrase</source>
<translation>Ponovite novo geslo</translation>
</message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Odkleni denarnico</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Odšifriraj denarnico</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
@@ -261,10 +309,6 @@
<source>Processing blocks on disk...</source>
<translation>Obdelava blokov na disku ...</translation>
</message>
- <message>
- <source>No block source available...</source>
- <translation>Ni virov za prenos blokov ...</translation>
- </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation><numerusform>%n obdelan blok zgodovine transakcij.</numerusform><numerusform>%n obdelana bloka zgodovine transakcij.</numerusform><numerusform>%n obdelani bloki zgodovine transakcij.</numerusform><numerusform>%n obdelanih blokov zgodovine transakcij.</numerusform></translation>
@@ -422,6 +466,10 @@
<source>Confirmed</source>
<translation>Potrjeno</translation>
</message>
+ <message>
+ <source>(no label)</source>
+ <translation>(brez oznake)</translation>
+ </message>
</context>
<context>
<name>EditAddressDialog</name>
@@ -1194,9 +1242,25 @@
<source>&amp;Save Image...</source>
<translation>&amp;Shrani sliko ...</translation>
</message>
+ <message>
+ <source>Address</source>
+ <translation>Naslov</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Oznaka</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Oznaka</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(brez oznake)</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -1340,7 +1404,11 @@
<source>S&amp;end</source>
<translation>&amp;Pošlji</translation>
</message>
- </context>
+ <message>
+ <source>(no label)</source>
+ <translation>(brez oznake)</translation>
+ </message>
+</context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -1543,9 +1611,29 @@
</context>
<context>
<name>TransactionTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Oznaka</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(brez oznake)</translation>
+ </message>
</context>
<context>
<name>TransactionView</name>
+ <message>
+ <source>Label</source>
+ <translation>Oznaka</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Naslov</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Podatkov ni bilo mogoče izvoziti.</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
diff --git a/src/qt/locale/bitcoin_sr.ts b/src/qt/locale/bitcoin_sr.ts
index 0fda9b9350..f880dd227e 100644
--- a/src/qt/locale/bitcoin_sr.ts
+++ b/src/qt/locale/bitcoin_sr.ts
@@ -37,6 +37,22 @@
<source>&amp;Delete</source>
<translation>&amp;Избриши</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Izbirajte adresu za slanje</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Izbirajte adresu za primanje</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Adresa za slanje</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Adresa za primanje</translation>
+ </message>
</context>
<context>
<name>AddressTableModel</name>
@@ -146,6 +162,10 @@
<translation>Трака са картицама</translation>
</message>
<message>
+ <source>Error</source>
+ <translation>Greška</translation>
+ </message>
+ <message>
<source>Up to date</source>
<translation>Ажурно</translation>
</message>
@@ -220,6 +240,10 @@
</context>
<context>
<name>Intro</name>
+ <message>
+ <source>Error</source>
+ <translation>Greška</translation>
+ </message>
</context>
<context>
<name>ModalOverlay</name>
@@ -278,6 +302,14 @@
</context>
<context>
<name>RPCConsole</name>
+ <message>
+ <source>Yes</source>
+ <translation>Da</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Ne</translation>
+ </message>
</context>
<context>
<name>ReceiveCoinsDialog</name>
@@ -293,6 +325,10 @@
<source>&amp;Message:</source>
<translation>Poruka:</translation>
</message>
+ <message>
+ <source>Show</source>
+ <translation>Prikaži</translation>
+ </message>
</context>
<context>
<name>ReceiveRequestDialog</name>
@@ -348,7 +384,11 @@
</context>
<context>
<name>SendConfirmationDialog</name>
- </context>
+ <message>
+ <source>Yes</source>
+ <translation>Da</translation>
+ </message>
+</context>
<context>
<name>ShutdownWindow</name>
</context>
@@ -432,6 +472,10 @@
<translation>učitavam adrese....</translation>
</message>
<message>
+ <source>Insufficient funds</source>
+ <translation>Nedovoljno sredstava</translation>
+ </message>
+ <message>
<source>Loading block index...</source>
<translation>Učitavam blok indeksa...</translation>
</message>
@@ -447,5 +491,9 @@
<source>Done loading</source>
<translation>Završeno učitavanje</translation>
</message>
- </context>
+ <message>
+ <source>Error</source>
+ <translation>Greška</translation>
+ </message>
+</context>
</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_sv.ts b/src/qt/locale/bitcoin_sv.ts
index 4d45d20cbf..ac5426f191 100644
--- a/src/qt/locale/bitcoin_sv.ts
+++ b/src/qt/locale/bitcoin_sv.ts
@@ -3,7 +3,7 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation>Högerklicka för att ändra adressen eller etiketten.</translation>
+ <translation>Högerklicka för att ändra adressen eller etiketten</translation>
</message>
<message>
<source>Create a new address</source>
@@ -319,6 +319,22 @@ Var vänlig och försök igen.</translation>
<translation>Öppna &amp;URI...</translation>
</message>
<message>
+ <source>Click to disable network activity.</source>
+ <translation>Klicka för att inaktivera nätverksaktivitet.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>Nätverksaktivitet inaktiverad.</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>Klicka för att aktivera nätverksaktivitet igen.</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>Synkar huvuden (%1%)...</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>Återindexerar block på disken...</translation>
</message>
@@ -430,10 +446,6 @@ Var vänlig och försök igen.</translation>
<source>Processing blocks on disk...</source>
<translation>Bearbetar block på disken...</translation>
</message>
- <message>
- <source>No block source available...</source>
- <translation>Ingen block-källa tillgänglig...</translation>
- </message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation><numerusform>Bearbetade %n block av transaktionshistoriken.</numerusform><numerusform>Bearbetade %n block av transaktionshistoriken.</numerusform></translation>
@@ -475,6 +487,10 @@ Var vänlig och försök igen.</translation>
<translation>%1-klient</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>Ansluter till noder...</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>Hämtar senaste...</translation>
</message>
@@ -517,6 +533,14 @@ Var vänlig och försök igen.</translation>
<translation>Inkommande transaktion</translation>
</message>
<message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation>HD-nyckelgenerering är &lt;b&gt;aktiverad&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation>HD-nyckelgenerering är &lt;b&gt;inaktiverad&lt;/b&gt;</translation>
+ </message>
+ <message>
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
<translation>Denna plånbok är &lt;b&gt;krypterad&lt;/b&gt; och för närvarande &lt;b&gt;olåst&lt;/b&gt;</translation>
</message>
@@ -524,7 +548,11 @@ Var vänlig och försök igen.</translation>
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Denna plånbok är &lt;b&gt;krypterad&lt;/b&gt; och för närvarande &lt;b&gt;låst&lt;/b&gt;</translation>
</message>
- </context>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>Ett kritiskt fel uppstod. Bitcoin kan inte fortsätta att köra säkert och kommer att avslutas.</translation>
+ </message>
+</context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -608,10 +636,74 @@ Var vänlig och försök igen.</translation>
<translation>Kopiera belopp</translation>
</message>
<message>
+ <source>Copy transaction ID</source>
+ <translation>Kopiera transaktions-ID</translation>
+ </message>
+ <message>
+ <source>Lock unspent</source>
+ <translation>Lås ospenderat</translation>
+ </message>
+ <message>
+ <source>Unlock unspent</source>
+ <translation>Lås upp ospenderat</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Kopiera kvantitet</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Kopiera avgift</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Kopiera efter avgift</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Kopiera byte</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Kopiera damm</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Kopiera växel</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation>(%1 låst)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>ja</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>nej</translation>
+ </message>
+ <message>
+ <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
+ <translation>Denna etikett blir röd om någon mottagare får en betalning som är mindre än aktuella dammtröskeln.</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation>Kan variera +/- %1 satoshi per inmatning.</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(Ingen etikett)</translation>
</message>
- </context>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation>växel från %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(växel)</translation>
+ </message>
+</context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -634,7 +726,39 @@ Var vänlig och försök igen.</translation>
<source>&amp;Address</source>
<translation>&amp;Adress</translation>
</message>
- </context>
+ <message>
+ <source>New receiving address</source>
+ <translation>Ny mottagaradress</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Ny avsändaradress</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Redigera mottagaradress</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Redigera avsändaradress</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>Den angivna adressen "%1" är inte en giltig Bitcoin-adress.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book.</source>
+ <translation>Den angivna adressen "%1" finns redan i adressboken.</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Kunde inte låsa upp plånboken.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Misslyckades med generering av ny nyckel.</translation>
+ </message>
+</context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -647,7 +771,7 @@ Var vänlig och försök igen.</translation>
</message>
<message>
<source>Directory already exists. Add %1 if you intend to create a new directory here.</source>
- <translation>Katalogen finns redan. Läggtill %1 om du vill skapa en ny katalog här.</translation>
+ <translation>Katalogen finns redan. Lägg till %1 om du vill skapa en ny katalog här.</translation>
</message>
<message>
<source>Path already exists, and is not a directory.</source>
@@ -763,14 +887,46 @@ Var vänlig och försök igen.</translation>
<translation>Formulär</translation>
</message>
<message>
+ <source>Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source>
+ <translation>Nyligen gjorda transaktioner visas inte korrekt och därför kan ditt din plånboks saldo visas felaktigt. Denna information kommer att visas korrekt så snart din plånbok har synkroniserat klart med bitcoin nätverket, enligt detaljer nedan.</translation>
+ </message>
+ <message>
+ <source>Number of blocks left</source>
+ <translation>Antal block kvar</translation>
+ </message>
+ <message>
+ <source>Unknown...</source>
+ <translation>Okänt...</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation>Sista blocktid</translation>
</message>
<message>
+ <source>Progress</source>
+ <translation>Förlopp</translation>
+ </message>
+ <message>
+ <source>Progress increase per hour</source>
+ <translation>Framstegssökning per timme</translation>
+ </message>
+ <message>
+ <source>calculating...</source>
+ <translation>beräknar...</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation>Beräknad tid kvar tills synkroniserad</translation>
+ </message>
+ <message>
<source>Hide</source>
<translation>Göm</translation>
</message>
- </context>
+ <message>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation>Okänd. Synkar huvuden (%1)...</translation>
+ </message>
+</context>
<context>
<name>OpenURIDialog</name>
<message>
@@ -789,7 +945,11 @@ Var vänlig och försök igen.</translation>
<source>Select payment request file</source>
<translation>Välj betalningsbegäransfil</translation>
</message>
- </context>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>Välj betalningsförfrågningsfil som ska öppnas</translation>
+ </message>
+</context>
<context>
<name>OptionsDialog</name>
<message>
@@ -1102,7 +1262,95 @@ Var vänlig och försök igen.</translation>
</context>
<context>
<name>PaymentServer</name>
- </context>
+ <message>
+ <source>Payment request error</source>
+ <translation>Fel vid betalningsbegäran</translation>
+ </message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation>Kan inte starta bitcoin: klicka-och-betala handhavare</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation>URI-hantering</translation>
+ </message>
+ <message>
+ <source>Payment request fetch URL is invalid: %1</source>
+ <translation>Hämtningsadressen för betalningsförfrågan är ogiltig: %1</translation>
+ </message>
+ <message>
+ <source>Invalid payment address %1</source>
+ <translation>Ogiltig betalningsadress %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 kan inte tolkas! Detta kan orsakas av en ogiltig Bitcoin-adress eller felaktiga URI parametrar.</translation>
+ </message>
+ <message>
+ <source>Payment request file handling</source>
+ <translation>Hantering av betalningsförfrågningsfil</translation>
+ </message>
+ <message>
+ <source>Payment request file cannot be read! This can be caused by an invalid payment request file.</source>
+ <translation>Betalningsförfrågningsfilen kan inte läsas! Detta kan orsakas av en felaktig betalningsförfrågnigsfil.</translation>
+ </message>
+ <message>
+ <source>Payment request rejected</source>
+ <translation>Betalningsbegäran avslogs</translation>
+ </message>
+ <message>
+ <source>Payment request network doesn't match client network.</source>
+ <translation>Betalningsbegärans nätverk matchar inte klientens nätverk.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Betalningsbegäran löpte ut.</translation>
+ </message>
+ <message>
+ <source>Payment request is not initialized.</source>
+ <translation>Betalningsbegäran är inte initierad.</translation>
+ </message>
+ <message>
+ <source>Unverified payment requests to custom payment scripts are unsupported.</source>
+ <translation>Overifierade betalningsförfrågningar till anpassade betalningsskript stöds inte.</translation>
+ </message>
+ <message>
+ <source>Invalid payment request.</source>
+ <translation>Ogiltig betalningsbegäran.</translation>
+ </message>
+ <message>
+ <source>Requested payment amount of %1 is too small (considered dust).</source>
+ <translation>Begärd betalning av %1 är för liten (betraktas som damm).</translation>
+ </message>
+ <message>
+ <source>Refund from %1</source>
+ <translation>Återbetalning från %1</translation>
+ </message>
+ <message>
+ <source>Payment request %1 is too large (%2 bytes, allowed %3 bytes).</source>
+ <translation>Betalningsbegäran %1 är för stor (%2 bytes, tillåten %3 bytes).</translation>
+ </message>
+ <message>
+ <source>Error communicating with %1: %2</source>
+ <translation>Kommunikationsfel med %1: %2</translation>
+ </message>
+ <message>
+ <source>Payment request cannot be parsed!</source>
+ <translation>Betalningsbegäran kan inte behandlas!</translation>
+ </message>
+ <message>
+ <source>Bad response from server %1</source>
+ <translation>Felaktigt svar från server %1</translation>
+ </message>
+ <message>
+ <source>Network request error</source>
+ <translation>Fel vid närverksbegäran</translation>
+ </message>
+ <message>
+ <source>Payment acknowledged</source>
+ <translation>Betalningen bekräftad</translation>
+ </message>
+</context>
<context>
<name>PeerTableModel</name>
<message>
@@ -1113,7 +1361,11 @@ Var vänlig och försök igen.</translation>
<source>Node/Service</source>
<translation>Nod/Tjänst</translation>
</message>
- </context>
+ <message>
+ <source>Ping</source>
+ <translation>Ping</translation>
+ </message>
+</context>
<context>
<name>QObject</name>
<message>
@@ -1152,17 +1404,73 @@ Var vänlig och försök igen.</translation>
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation><numerusform>%n sekund</numerusform><numerusform>%n sekunder</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation><numerusform>%n minut</numerusform><numerusform>%n minuter</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation><numerusform>%n timme</numerusform><numerusform>%n timmar</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation><numerusform>%n dag</numerusform><numerusform>%n dagar</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation><numerusform>%n vecka</numerusform><numerusform>%n veckor</numerusform></translation>
+ </message>
<message>
<source>%1 and %2</source>
<translation>%1 och %2</translation>
</message>
- </context>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation><numerusform>%n år</numerusform><numerusform>%n år</numerusform></translation>
+ </message>
+ <message>
+ <source>%1 didn't yet exit safely...</source>
+ <translation>%1 avslutades inte ännu säkert...</translation>
+ </message>
+</context>
<context>
<name>QObject::QObject</name>
- </context>
+ <message>
+ <source>Error: Specified data directory "%1" does not exist.</source>
+ <translation>Fel: Den angivna datakatalogen "%1" finns inte.</translation>
+ </message>
+ <message>
+ <source>Error: Cannot parse configuration file: %1. Only use key=value syntax.</source>
+ <translation>Fel: Kan inte läsa konfigurationsfilen: %1. Använd bara nyckel=värde formatet.</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation>Fel: %1</translation>
+ </message>
+</context>
<context>
<name>QRImageWidget</name>
- </context>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;Spara Bild...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>&amp;Kopiera Bild</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>Spara QR-kod</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>PNG-bild (*.png)</translation>
+ </message>
+</context>
<context>
<name>RPCConsole</name>
<message>
@@ -1382,6 +1690,18 @@ Var vänlig och försök igen.</translation>
<translation>1 &amp;år</translation>
</message>
<message>
+ <source>&amp;Disconnect</source>
+ <translation>&amp;Koppla ner</translation>
+ </message>
+ <message>
+ <source>Ban for</source>
+ <translation>Blockera i</translation>
+ </message>
+ <message>
+ <source>&amp;Unban</source>
+ <translation>&amp;Ta bort blockering</translation>
+ </message>
+ <message>
<source>Welcome to the %1 RPC console.</source>
<translation>Välkommen till %1 RPC-konsolen.</translation>
</message>
@@ -1394,6 +1714,10 @@ Var vänlig och försök igen.</translation>
<translation>Skriv &lt;b&gt;help&lt;/b&gt; för en översikt av alla kommandon.</translation>
</message>
<message>
+ <source>Network activity disabled</source>
+ <translation>Nätverksaktivitet inaktiverad</translation>
+ </message>
+ <message>
<source>%1 B</source>
<translation>%1 B</translation>
</message>
@@ -1513,10 +1837,18 @@ Var vänlig och försök igen.</translation>
<translation>Ta bort</translation>
</message>
<message>
+ <source>Copy URI</source>
+ <translation>Kopiera URI</translation>
+ </message>
+ <message>
<source>Copy label</source>
<translation>Kopiera etikett</translation>
</message>
<message>
+ <source>Copy message</source>
+ <translation>Kopiera meddelande</translation>
+ </message>
+ <message>
<source>Copy amount</source>
<translation>Kopiera belopp</translation>
</message>
@@ -1540,25 +1872,73 @@ Var vänlig och försök igen.</translation>
<translation>&amp;Spara Bild...</translation>
</message>
<message>
+ <source>Request payment to %1</source>
+ <translation>Begär betalning till %1</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>Betalinformaton</translation>
+ </message>
+ <message>
+ <source>URI</source>
+ <translation>URI</translation>
+ </message>
+ <message>
<source>Address</source>
<translation>Adress</translation>
</message>
<message>
+ <source>Amount</source>
+ <translation>Belopp:</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>Etikett</translation>
</message>
- </context>
+ <message>
+ <source>Message</source>
+ <translation>Meddelande</translation>
+ </message>
+ <message>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation>URI:n är för lång, försöka minska texten för etikett / meddelande.</translation>
+ </message>
+ <message>
+ <source>Error encoding URI into QR Code.</source>
+ <translation>Fel vid skapande av QR-kod från URI.</translation>
+ </message>
+</context>
<context>
<name>RecentRequestsTableModel</name>
<message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>Etikett</translation>
</message>
<message>
+ <source>Message</source>
+ <translation>Meddelande</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(Ingen etikett)</translation>
</message>
- </context>
+ <message>
+ <source>(no message)</source>
+ <translation>(inget meddelande)</translation>
+ </message>
+ <message>
+ <source>(no amount requested)</source>
+ <translation>(ingen summa begärd)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation>Begärd</translation>
+ </message>
+</context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1686,6 +2066,10 @@ Var vänlig och försök igen.</translation>
<translation>Damm:</translation>
</message>
<message>
+ <source>Confirmation time target:</source>
+ <translation>Bekräftelsestidsmål:</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>Rensa &amp;alla</translation>
</message>
@@ -1702,10 +2086,118 @@ Var vänlig och försök igen.</translation>
<translation>&amp;Skicka</translation>
</message>
<message>
+ <source>Copy quantity</source>
+ <translation>Kopiera kvantitet</translation>
+ </message>
+ <message>
<source>Copy amount</source>
<translation>Kopiera belopp</translation>
</message>
<message>
+ <source>Copy fee</source>
+ <translation>Kopiera avgift</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Kopiera efter avgift</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Kopiera byte</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Kopiera damm</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Kopiera växel</translation>
+ </message>
+ <message>
+ <source>%1 to %2</source>
+ <translation>%1 till %2</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to send?</source>
+ <translation>Är du säker på att du vill skicka?</translation>
+ </message>
+ <message>
+ <source>added as transaction fee</source>
+ <translation>adderad som transaktionsavgift</translation>
+ </message>
+ <message>
+ <source>Total Amount %1</source>
+ <translation>Totalt belopp %1</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>eller</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation>Bekräfta skickade mynt</translation>
+ </message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>Mottagarens adress är ogiltig. Kontrollera igen.</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation>Det betalade beloppet måste vara större än 0.</translation>
+ </message>
+ <message>
+ <source>The amount exceeds your balance.</source>
+ <translation>Värdet överstiger ditt saldo.</translation>
+ </message>
+ <message>
+ <source>The total exceeds your balance when the %1 transaction fee is included.</source>
+ <translation>Totalvärdet överstiger ditt saldo när transaktionsavgiften %1 är pålagd.</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation>Duplicerad adress upptäckt: adresser skall endast användas en gång var.</translation>
+ </message>
+ <message>
+ <source>Transaction creation failed!</source>
+ <translation>Transaktionen gick inte att skapa!</translation>
+ </message>
+ <message>
+ <source>The transaction was rejected with the following reason: %1</source>
+ <translation>Transaktionen avvisades med följande orsak: %1</translation>
+ </message>
+ <message>
+ <source>A fee higher than %1 is considered an absurdly high fee.</source>
+ <translation>En avgift högre än %1 anses vara en absurd hög avgift.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Betalningsbegäran löpte ut.</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n block(s)</source>
+ <translation><numerusform>%n block</numerusform><numerusform>%n block</numerusform></translation>
+ </message>
+ <message>
+ <source>Pay only the required fee of %1</source>
+ <translation>Betala endast den nödvändiga avgiften på %1</translation>
+ </message>
+ <message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>Varning: Felaktig Bitcoinadress</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <translation>Varning: Okänd växeladress</translation>
+ </message>
+ <message>
+ <source>Confirm custom change address</source>
+ <translation>Bekräfta anpassad växlingsadress</translation>
+ </message>
+ <message>
+ <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source>
+ <translation>Den adress du valt för växel ingår inte i denna plånbok. Eventuella eller alla pengar i din plånbok kan skickas till den här adressen. Är du säker?</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(Ingen etikett)</translation>
</message>
@@ -1788,10 +2280,18 @@ Var vänlig och försök igen.</translation>
<source>Memo:</source>
<translation>PM:</translation>
</message>
- </context>
+ <message>
+ <source>Enter a label for this address to add it to your address book</source>
+ <translation>Ange en etikett för den här adressen och lägg till den i din adressbok</translation>
+ </message>
+</context>
<context>
<name>SendConfirmationDialog</name>
- </context>
+ <message>
+ <source>Yes</source>
+ <translation>Ja</translation>
+ </message>
+</context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1889,7 +2389,59 @@ Var vänlig och försök igen.</translation>
<source>Reset all verify message fields</source>
<translation>Rensa alla fält</translation>
</message>
- </context>
+ <message>
+ <source>Click "Sign Message" to generate signature</source>
+ <translation>Klicka "Signera Meddelande" för att få en signatur</translation>
+ </message>
+ <message>
+ <source>The entered address is invalid.</source>
+ <translation>Den angivna adressen är ogiltig.</translation>
+ </message>
+ <message>
+ <source>Please check the address and try again.</source>
+ <translation>Vad god kontrollera adressen och försök igen.</translation>
+ </message>
+ <message>
+ <source>The entered address does not refer to a key.</source>
+ <translation>Den angivna adressen refererar inte till en nyckel.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock was cancelled.</source>
+ <translation>Upplåsningen av plånboken avbröts.</translation>
+ </message>
+ <message>
+ <source>Private key for the entered address is not available.</source>
+ <translation>Privata nyckel för den angivna adressen är inte tillgänglig.</translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation>Signeringen av meddelandet misslyckades.</translation>
+ </message>
+ <message>
+ <source>Message signed.</source>
+ <translation>Meddelande signerat.</translation>
+ </message>
+ <message>
+ <source>The signature could not be decoded.</source>
+ <translation>Signaturen kunde inte avkodas.</translation>
+ </message>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation>Kontrollera signaturen och försök igen.</translation>
+ </message>
+ <message>
+ <source>The signature did not match the message digest.</source>
+ <translation>Signaturen matchade inte meddelandesammanfattningen.</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation>Meddelandeverifikation misslyckades.</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation>Meddelande verifierat.</translation>
+ </message>
+</context>
<context>
<name>SplashScreen</name>
<message>
@@ -1906,28 +2458,336 @@ Var vänlig och försök igen.</translation>
</context>
<context>
<name>TransactionDesc</name>
- </context>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>Öppet för %n mer block</numerusform><numerusform>Öppet för %n mer block</numerusform></translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>Öppet till %1</translation>
+ </message>
+ <message>
+ <source>conflicted with a transaction with %1 confirmations</source>
+ <translation>konflikt med en transaktion med %1 konfirmationer</translation>
+ </message>
+ <message>
+ <source>%1/offline</source>
+ <translation>%1/nerkopplad</translation>
+ </message>
+ <message>
+ <source>0/unconfirmed, %1</source>
+ <translation>0/obekräftade, %1</translation>
+ </message>
+ <message>
+ <source>in memory pool</source>
+ <translation>i minnespoolen</translation>
+ </message>
+ <message>
+ <source>not in memory pool</source>
+ <translation>ej i minnespoolen</translation>
+ </message>
+ <message>
+ <source>abandoned</source>
+ <translation>övergiven</translation>
+ </message>
+ <message>
+ <source>%1/unconfirmed</source>
+ <translation>%1/obekräftade</translation>
+ </message>
+ <message>
+ <source>%1 confirmations</source>
+ <translation>%1 bekräftelser</translation>
+ </message>
+ <message>
+ <source>Status</source>
+ <translation>Status</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ <message>
+ <source>Source</source>
+ <translation>Källa</translation>
+ </message>
+ <message>
+ <source>Generated</source>
+ <translation>Genererad</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>Från</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>okänd</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation>Till</translation>
+ </message>
+ <message>
+ <source>own address</source>
+ <translation>egen adress</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>granska-bara</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>etikett</translation>
+ </message>
+ <message numerus="yes">
+ <source>matures in %n more block(s)</source>
+ <translation><numerusform>mognar om %n mer block</numerusform><numerusform>mognar om %n fler block</numerusform></translation>
+ </message>
+ <message>
+ <source>not accepted</source>
+ <translation>inte accepterad</translation>
+ </message>
+ <message>
+ <source>Debit</source>
+ <translation>Belasta</translation>
+ </message>
+ <message>
+ <source>Transaction fee</source>
+ <translation>Transaktionsavgift</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Meddelande</translation>
+ </message>
+ <message>
+ <source>Comment</source>
+ <translation>Kommentar</translation>
+ </message>
+ <message>
+ <source>Transaction ID</source>
+ <translation>Transaktions-ID</translation>
+ </message>
+ <message>
+ <source>Transaction total size</source>
+ <translation>Transaktionens totala storlek</translation>
+ </message>
+ <message>
+ <source>Merchant</source>
+ <translation>Handlare</translation>
+ </message>
+ <message>
+ <source>Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source>
+ <translation>Genererade mynt måste vänta %1 block innan de kan användas. När du skapade detta block sändes det till nätverket för att läggas till i blockkedjan. Om blocket inte kommer in i kedjan kommer dess status att ändras till "accepteras inte" och kommer ej att gå att spendera. Detta kan ibland hända om en annan nod genererar ett block nästan samtidigt som dig.</translation>
+ </message>
+ <message>
+ <source>Debug information</source>
+ <translation>Debug information</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation>Transaktion</translation>
+ </message>
+ <message>
+ <source>Inputs</source>
+ <translation>Inmatningar</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Belopp:</translation>
+ </message>
+ <message>
+ <source>true</source>
+ <translation>sant</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation>falsk</translation>
+ </message>
+</context>
<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Den här panelen visar en detaljerad beskrivning av transaktionen</translation>
</message>
- </context>
+ <message>
+ <source>Details for %1</source>
+ <translation>Detaljer för %1</translation>
+ </message>
+</context>
<context>
<name>TransactionTableModel</name>
<message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Typ</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>Etikett</translation>
</message>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>Öppet för %n mer block</numerusform><numerusform>Öppet för %n mer block</numerusform></translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>Öppet till %1</translation>
+ </message>
+ <message>
+ <source>Offline</source>
+ <translation>Nerkopplad</translation>
+ </message>
+ <message>
+ <source>Unconfirmed</source>
+ <translation>Obekräftade:</translation>
+ </message>
+ <message>
+ <source>Abandoned</source>
+ <translation>Övergiven</translation>
+ </message>
+ <message>
+ <source>Confirming (%1 of %2 recommended confirmations)</source>
+ <translation>Bekräftar (%1 av %2 bekräftelser)</translation>
+ </message>
+ <message>
+ <source>Confirmed (%1 confirmations)</source>
+ <translation>Bekräftad (%1 bekräftelser)</translation>
+ </message>
+ <message>
+ <source>Conflicted</source>
+ <translation>Konflikt</translation>
+ </message>
+ <message>
+ <source>Immature (%1 confirmations, will be available after %2)</source>
+ <translation>Omogen (%1 bekräftelser, blir tillgänglig efter %2)</translation>
+ </message>
+ <message>
+ <source>This block was not received by any other nodes and will probably not be accepted!</source>
+ <translation>Det här blocket togs inte emot av några andra noder och kommer antagligen inte att bli accepterad!</translation>
+ </message>
+ <message>
+ <source>Generated but not accepted</source>
+ <translation>Genererad men inte accepterad</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Mottagen med</translation>
+ </message>
+ <message>
+ <source>Received from</source>
+ <translation>Mottaget från</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Skickad till</translation>
+ </message>
+ <message>
+ <source>Payment to yourself</source>
+ <translation>Betalning till dig själv</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Genererade</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>granska-bara</translation>
+ </message>
+ <message>
+ <source>(n/a)</source>
+ <translation>(n/a)</translation>
+ </message>
<message>
<source>(no label)</source>
<translation>(Ingen etikett)</translation>
</message>
- </context>
+ <message>
+ <source>Transaction status. Hover over this field to show number of confirmations.</source>
+ <translation>Transaktionsstatus. Håll muspekaren över för att se antal bekräftelser.</translation>
+ </message>
+ <message>
+ <source>Date and time that the transaction was received.</source>
+ <translation>Tidpunkt då transaktionen mottogs.</translation>
+ </message>
+ <message>
+ <source>Type of transaction.</source>
+ <translation>Transaktionstyp.</translation>
+ </message>
+ <message>
+ <source>Whether or not a watch-only address is involved in this transaction.</source>
+ <translation>Anger om granska-bara--adresser är involverade i denna transaktion.</translation>
+ </message>
+ <message>
+ <source>User-defined intent/purpose of the transaction.</source>
+ <translation>Användardefinierat syfte/ändamål för transaktionen.</translation>
+ </message>
+ <message>
+ <source>Amount removed from or added to balance.</source>
+ <translation>Belopp draget eller tillagt till balans.</translation>
+ </message>
+</context>
<context>
<name>TransactionView</name>
<message>
+ <source>All</source>
+ <translation>Alla</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>Idag</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>Denna vecka</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>Denna månad</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>Föregående månad</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>Det här året</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Mottagen med</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Skickad till</translation>
+ </message>
+ <message>
+ <source>To yourself</source>
+ <translation>Till dig själv</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Genererade</translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation>Övriga</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation>Ange en adress eller etikett att söka efter</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation>Minsta belopp</translation>
+ </message>
+ <message>
+ <source>Abandon transaction</source>
+ <translation>Avbryt transaktionen</translation>
+ </message>
+ <message>
<source>Copy address</source>
<translation>Kopiera adress</translation>
</message>
@@ -1940,10 +2800,50 @@ Var vänlig och försök igen.</translation>
<translation>Kopiera belopp</translation>
</message>
<message>
+ <source>Copy transaction ID</source>
+ <translation>Kopiera transaktions-ID</translation>
+ </message>
+ <message>
+ <source>Copy raw transaction</source>
+ <translation>Kopiera rå transaktion</translation>
+ </message>
+ <message>
+ <source>Copy full transaction details</source>
+ <translation>Kopiera alla transaktionsdetaljerna</translation>
+ </message>
+ <message>
+ <source>Edit label</source>
+ <translation>Ändra etikett</translation>
+ </message>
+ <message>
+ <source>Show transaction details</source>
+ <translation>Visa transaktionsdetaljer</translation>
+ </message>
+ <message>
+ <source>Export Transaction History</source>
+ <translation>Exportera Transaktionshistoriken</translation>
+ </message>
+ <message>
<source>Comma separated file (*.csv)</source>
<translation>Kommaseparerad fil (*.csv)</translation>
</message>
<message>
+ <source>Confirmed</source>
+ <translation>Bekräftad</translation>
+ </message>
+ <message>
+ <source>Watch-only</source>
+ <translation>Enbart granskning</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Datum</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Typ</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>Etikett</translation>
</message>
@@ -1952,26 +2852,86 @@ Var vänlig och försök igen.</translation>
<translation>Adress</translation>
</message>
<message>
+ <source>ID</source>
+ <translation>ID</translation>
+ </message>
+ <message>
<source>Exporting Failed</source>
<translation>Export misslyckades</translation>
</message>
- </context>
+ <message>
+ <source>There was an error trying to save the transaction history to %1.</source>
+ <translation>Det inträffade ett fel när transaktionshistoriken skulle sparas till %1.</translation>
+ </message>
+ <message>
+ <source>Exporting Successful</source>
+ <translation>Exporteringen lyckades</translation>
+ </message>
+ <message>
+ <source>The transaction history was successfully saved to %1.</source>
+ <translation>Transaktionshistoriken sparades utan problem till %1.</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>till</translation>
+ </message>
+</context>
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
<source>Unit to show amounts in. Click to select another unit.</source>
- <translation>&amp;Enhet att visa belopp i. Klicka för att välja annan enhet.</translation>
+ <translation>Enhet att visa belopp i. Klicka för att välja annan enhet.</translation>
</message>
</context>
<context>
<name>WalletFrame</name>
- </context>
+ <message>
+ <source>No wallet has been loaded.</source>
+ <translation>Ingen plånbok har laddats in.</translation>
+ </message>
+</context>
<context>
<name>WalletModel</name>
- </context>
+ <message>
+ <source>Send Coins</source>
+ <translation>Skicka Bitcoins</translation>
+ </message>
+</context>
<context>
<name>WalletView</name>
- </context>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;Exportera</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Exportera informationen i den nuvarande fliken till en fil</translation>
+ </message>
+ <message>
+ <source>Backup Wallet</source>
+ <translation>Säkerhetskopiera Plånbok</translation>
+ </message>
+ <message>
+ <source>Wallet Data (*.dat)</source>
+ <translation>Plånboks-data (*.dat)</translation>
+ </message>
+ <message>
+ <source>Backup Failed</source>
+ <translation>Säkerhetskopiering misslyckades</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the wallet data to %1.</source>
+ <translation>Det inträffade ett fel när plånbokens data skulle sparas till %1.</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation>Säkerhetskopiering lyckades</translation>
+ </message>
+ <message>
+ <source>The wallet data was successfully saved to %1.</source>
+ <translation>Plånbokens data sparades utan problem till %1.</translation>
+ </message>
+</context>
<context>
<name>bitcoin-core</name>
<message>
@@ -1995,6 +2955,18 @@ Var vänlig och försök igen.</translation>
<translation>Tillåt kommandon från kommandotolken och JSON-RPC-kommandon</translation>
</message>
<message>
+ <source>Accept connections from outside (default: 1 if no -proxy or -connect/-noconnect)</source>
+ <translation>Acceptera anslutningar utifrån (förvalt: 1 om ingen -proxy eller -connect/-noconnect)</translation>
+ </message>
+ <message>
+ <source>Connect only to the specified node(s); -noconnect or -connect=0 alone to disable automatic connections</source>
+ <translation>Anslut endast till angivna nod(er); -noconnect eller -connect=0 ensam för att inaktivera automatiska anslutningar</translation>
+ </message>
+ <message>
+ <source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
+ <translation>Distribuerad under MIT mjukvarulicens, se den bifogade filen %s eller %s</translation>
+ </message>
+ <message>
<source>If &lt;category&gt; is not supplied or if &lt;category&gt; = 1, output all debugging information.</source>
<translation>Om &lt;kategori&gt; inte anges eller om &lt;category&gt; = 1, visa all avlusningsinformation.</translation>
</message>
@@ -2007,10 +2979,6 @@ Var vänlig och försök igen.</translation>
<translation>Beskärning: sista plånbokssynkroniseringen ligger utanför beskuren data. Du måste använda -reindex (ladda ner hela blockkedjan igen eftersom noden beskurits)</translation>
</message>
<message>
- <source>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, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Minska lagringsbehovet genom att beskära (ta bort) gamla block. Detta läge är inkompatibelt med -txindex och -rescan. Varning: Ändras denna inställning måste hela blockkedjan laddas ner igen. (förvalt: 0 = inaktivera beskärning av block, &gt;%u = målstorlek i MiB att använda för blockfiler)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Omskanningar kan inte göras i beskuret läge. Du måste använda -reindex vilket kommer ladda ner hela blockkedjan igen.</translation>
</message>
@@ -2075,6 +3043,10 @@ Var vänlig och försök igen.</translation>
<translation>Exekvera kommando när en plånbokstransaktion ändras (%s i cmd är ersatt av TxID)</translation>
</message>
<message>
+ <source>Extra transactions to keep in memory for compact block reconstructions (default: %u)</source>
+ <translation>Extra transaktioner att hålla i minnet för kompakta blockrekonstruktioner (standard: %u)</translation>
+ </message>
+ <message>
<source>Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)</source>
<translation>Maximalt tillåten median-peer tidsoffset justering. Lokalt perspektiv av tiden kan bli påverkad av partners, framåt eller bakåt denna tidsrymd. (förvalt: %u sekunder)</translation>
</message>
@@ -2099,6 +3071,10 @@ Var vänlig och försök igen.</translation>
<translation>Blockdatabasen innehåller ett block som verkar vara från framtiden. Detta kan vara på grund av att din dators datum och tid är felaktiga. Bygg bara om blockdatabasen om du är säker på att datorns datum och tid är korrekt</translation>
</message>
<message>
+ <source>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source>
+ <translation>Detta är ett förhandstestbygge - använd på egen risk - använd inte för mining eller handels applikationer</translation>
+ </message>
+ <message>
<source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source>
<translation>Kan inte spola tillbaka databasen till obeskärt läge. Du måste ladda ner blockkedjan igen</translation>
</message>
@@ -2107,6 +3083,22 @@ Var vänlig och försök igen.</translation>
<translation>Använd UPnP för att mappa den lyssnande porten (förvalt: 1 när lyssning aktiverat och utan -proxy)</translation>
</message>
<message>
+ <source>Username and hashed password for JSON-RPC connections. The field &lt;userpw&gt; comes in the format: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=&lt;USERNAME&gt;/rpcpassword=&lt;PASSWORD&gt; pair of arguments. This option can be specified multiple times</source>
+ <translation>Användarnamn och hashat lösenord för JSON-RPC-anslutningar. Fältet &lt;userpw&gt; kommer i formatet: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. Ett kanoniskt pythonskript finns inkluderat i share/rpcuser. Klienten kopplas sedan normalt med rpcuser=&lt;USERNAME&gt;/rpcpassword=&lt;PASSWORD&gt; par argument. Detta alternativ kan anges flera gånger</translation>
+ </message>
+ <message>
+ <source>Wallet will not create transactions that violate mempool chain limits (default: %u)</source>
+ <translation>Plånboken skapar inte transaktioner som bryter mot mempools kedjegränser (förval: %u)</translation>
+ </message>
+ <message>
+ <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
+ <translation>Varning: Nätverket verkar inte vara helt överens! Några miners verkar ha problem.</translation>
+ </message>
+ <message>
+ <source>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source>
+ <translation>Varning: Vi verkar inte helt överens med våra peers! Du kan behöva uppgradera, eller andra noder kan behöva uppgradera.</translation>
+ </message>
+ <message>
<source>You need to rebuild the database using -reindex-chainstate to change -txindex</source>
<translation>Du måste återskapa databasen med -reindex-chainstate för att ändra -txindex</translation>
</message>
@@ -2335,6 +3327,10 @@ Var vänlig och försök igen.</translation>
<translation>Använd UPnP för att mappa den lyssnande porten (förvalt: %u)</translation>
</message>
<message>
+ <source>Use the test chain</source>
+ <translation>Använd testkedjan</translation>
+ </message>
+ <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation>Kommentaren i användaragent (%s) innehåller osäkra tecken.</translation>
</message>
@@ -2607,6 +3603,10 @@ Var vänlig och försök igen.</translation>
<translation>Avgifter (i %s/kB) mindre än detta anses vara nollavgifter vid skapande av transaktion (standard: %s)</translation>
</message>
<message>
+ <source>Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)</source>
+ <translation>Vidarebefordra alltid transaktioner från vitlistade noder även om de bryter mot den lokala reläpolicyn (förvalt: %d)</translation>
+ </message>
+ <message>
<source>How thorough the block verification of -checkblocks is (0-4, default: %u)</source>
<translation>Hur grundlig blockverifikationen vid -checkblocks är (0-4, förvalt: %u)</translation>
</message>
@@ -2623,10 +3623,22 @@ Var vänlig och försök igen.</translation>
<translation>Skriv ut avlusningsinformation (förvalt: %u, att ange &lt;category&gt; är frivilligt)</translation>
</message>
<message>
+ <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect/-noconnect)</source>
+ <translation>Sök efter klientadresser med DNS sökningen, om det finns otillräckligt med adresser (förvalt: 1 om inte -connect/-noconnect)</translation>
+ </message>
+ <message>
<source>Support filtering of blocks and transaction with bloom filters (default: %u)</source>
<translation>Stöd filtrering av block och transaktioner med bloomfilter (standard: %u)</translation>
</message>
<message>
+ <source>This is the transaction fee you may pay when fee estimates are not available.</source>
+ <translation>Detta är transaktionsavgiften du kan komma att betala om uppskattad avgift inte finns tillgänglig.</translation>
+ </message>
+ <message>
+ <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit %s and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
+ <translation>Denna produkten innehåller mjukvara utvecklad av OpenSSL Project för användning i OpenSSL Toolkit %s och kryptografisk mjukvara utvecklad av Eric Young samt UPnP-mjukvara skriven av Thomas Bernard.</translation>
+ </message>
+ <message>
<source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source>
<translation>Total längd på strängen för nätverksversion (%i) överskrider maxlängden (%i). Minska numret eller storleken på uacomments.</translation>
</message>
@@ -2655,6 +3667,10 @@ Var vänlig och försök igen.</translation>
<translation>Varning: Plånboksfilen var korrupt, datat har räddats! Den ursprungliga %s har sparas som %s i %s. Om ditt saldo eller transaktioner är felaktiga bör du återställa från en säkerhetskopia.</translation>
</message>
<message>
+ <source>%s is set very high!</source>
+ <translation>%s är satt väldigt högt!</translation>
+ </message>
+ <message>
<source>(default: %s)</source>
<translation>(förvalt: %s)</translation>
</message>
@@ -2739,10 +3755,38 @@ Var vänlig och försök igen.</translation>
<translation>Spendera okonfirmerad växel när transaktioner sänds (förvalt: %u)</translation>
</message>
<message>
+ <source>Starting network threads...</source>
+ <translation>Startar nätverkstrådar...</translation>
+ </message>
+ <message>
+ <source>The wallet will avoid paying less than the minimum relay fee.</source>
+ <translation>Plånboken undviker att betala mindre än lägsta reläavgift.</translation>
+ </message>
+ <message>
+ <source>This is the minimum transaction fee you pay on every transaction.</source>
+ <translation>Det här är minimum avgiften du kommer betala för varje transaktion. </translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you will pay if you send a transaction.</source>
+ <translation>Det här är transaktionsavgiften du kommer betala om du skickar en transaktion. </translation>
+ </message>
+ <message>
<source>Threshold for disconnecting misbehaving peers (default: %u)</source>
<translation>Tröskelvärde för att koppla ifrån klienter som missköter sig (förvalt: %u)</translation>
</message>
<message>
+ <source>Transaction amounts must not be negative</source>
+ <translation>Transaktionens belopp får ej vara negativ</translation>
+ </message>
+ <message>
+ <source>Transaction has too long of a mempool chain</source>
+ <translation>Transaktionen har för lång mempool-kedja</translation>
+ </message>
+ <message>
+ <source>Transaction must have at least one recipient</source>
+ <translation>Transaktionen måste ha minst en mottagare</translation>
+ </message>
+ <message>
<source>Unknown network specified in -onlynet: '%s'</source>
<translation>Okänt nätverk som anges i -onlynet: '%s'</translation>
</message>
diff --git a/src/qt/locale/bitcoin_th_TH.ts b/src/qt/locale/bitcoin_th_TH.ts
index 18e78847fc..ea84d11d39 100644
--- a/src/qt/locale/bitcoin_th_TH.ts
+++ b/src/qt/locale/bitcoin_th_TH.ts
@@ -41,6 +41,18 @@
<source>&amp;Delete</source>
<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>
</context>
<context>
<name>AddressTableModel</name>
@@ -273,10 +285,6 @@
<source>Processing blocks on disk...</source>
<translation>กำลังดำเนินการกับบล็อกในดิสก์...</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></translation>
diff --git a/src/qt/locale/bitcoin_tr.ts b/src/qt/locale/bitcoin_tr.ts
index d1249d09be..321effc7e1 100644
--- a/src/qt/locale/bitcoin_tr.ts
+++ b/src/qt/locale/bitcoin_tr.ts
@@ -35,7 +35,7 @@
</message>
<message>
<source>&amp;Export</source>
- <translation>&amp;Dışa aktar</translation>
+ <translation>&amp;Dışarı aktar</translation>
</message>
<message>
<source>&amp;Delete</source>
@@ -59,15 +59,23 @@
</message>
<message>
<source>Receiving addresses</source>
- <translation>Alınan adresler</translation>
+ <translation>Alım adresleri</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>Bunlar ödemeleri göndermek için kullanacağınız Bitcoin adreslerinizdir. Bitcoin yollamadan önce tutarı ve alıcının alım adresini her zaman kontrol ediniz.</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>Bunlar ödemeleri almak için kullanacağınız Bitcoin adreslerinizdir. Her işlem için yeni bir alım adresi kullanmanız tavsiye edilir.</translation>
</message>
<message>
<source>&amp;Copy Address</source>
- <translation>&amp;Adres Kopyala</translation>
+ <translation>&amp;Adresi Kopyala</translation>
</message>
<message>
<source>Copy &amp;Label</source>
- <translation>&amp;Etiketi kopyala</translation>
+ <translation>&amp;Etiketi Kopyala</translation>
</message>
<message>
<source>&amp;Edit</source>
@@ -75,13 +83,21 @@
</message>
<message>
<source>Export Address List</source>
- <translation>Adres listesini dışarı aktar</translation>
+ <translation>Adres Listesini Dışarı Aktar</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Virgülle ayrılmış değerler dosyası (*.csv)</translation>
</message>
<message>
<source>Exporting Failed</source>
- <translation>Dışarı aktarmada hata</translation>
+ <translation>Dışarı Aktarım Başarısız Oldu</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Adres listesinin %1 konumuna kaydedilmesi sırasında bir hata meydana geldi. Lütfen tekrar deneyin.</translation>
</message>
- </context>
+</context>
<context>
<name>AddressTableModel</name>
<message>
@@ -101,7 +117,7 @@
<name>AskPassphraseDialog</name>
<message>
<source>Passphrase Dialog</source>
- <translation>Parola diyaloğu</translation>
+ <translation>Parola Diyaloğu</translation>
</message>
<message>
<source>Enter passphrase</source>
@@ -116,8 +132,16 @@
<translation>Yeni parolayı tekrarlayınız</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>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>Encrypt wallet</source>
- <translation>Şifrelenmiş cüzdan</translation>
+ <translation>Cüzdanı şifrele</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Bu eylem cüzdan kilidini açmak için cüzdan parolanızı gerektirir.</translation>
</message>
<message>
<source>Unlock wallet</source>
@@ -125,17 +149,29 @@
</message>
<message>
<source>This operation needs your wallet passphrase to decrypt the wallet.</source>
- <translation>Bu işlem, cüzdan şifresini çözmek için cüzdan parolanıza ihtiyaç duyuyor.</translation>
+ <translation>Bu eylem, cüzdan şifresini çözmek için cüzdan parolanıza ihtiyaç duyuyor.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Cüzdanın şifrelemesini aç</translation>
</message>
<message>
<source>Change passphrase</source>
<translation>Parola değiştir</translation>
</message>
<message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Eski ve yeni parolanızı cüzdana giriniz.</translation>
+ </message>
+ <message>
<source>Confirm wallet encryption</source>
<translation>Cüzdan şifrelemesini onayla</translation>
</message>
<message>
+ <source>Warning: If you encrypt your wallet and lose your passphrase, you will &lt;b&gt;LOSE ALL OF YOUR BITCOINS&lt;/b&gt;!</source>
+ <translation>Uyarı: Eğer cüzdanınızı şifreler ve parolanızı kaybederseniz &lt;b&gt;TÜM BİTCOİNLERİNİZİ KAYBEDECEKSİNİZ&lt;/b&gt;!</translation>
+ </message>
+ <message>
<source>Are you sure you wish to encrypt your wallet?</source>
<translation>Cüzdanınızı şifrelemek istediğinizden emin misiniz?</translation>
</message>
@@ -144,34 +180,66 @@
<translation>Cüzdan şifrelendi</translation>
</message>
<message>
+ <source>%1 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şleminin bitirilmesi için %1 kapatılacak. Her ne kadar cüzdanınızı şifreleseniz de şifrelemenin bitcoinlerinizi bilgisayarınıza bulaşan zararlılardan tam olarak koruyamayacağını unutmayın.</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>
+ <message>
<source>Wallet encryption failed</source>
<translation>Cüzdan şifreleme başarısız</translation>
</message>
<message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Dahili bir hata yüzünden cüzdan şifrelemesi başarısız oldu. Cüzdanın şifrelenmedi.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>Girilen parolalar birbiriyle eşleşmiyor.</translation>
+ </message>
+ <message>
<source>Wallet unlock failed</source>
- <translation>Cüzdan kilidi kaldırma hatası</translation>
+ <translation>Cüzdan kilidini kaldırma başarısız oldu</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>Cüzdan şifresinin açılması için girilen parola yanlıştı.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Cüzdan şifresinin açılması başarısız oldu</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>Cüzdan parolası başarılı bir şekilde değiştirildi.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Uyarı: Caps Lock tuşu etkin durumda!</translation>
</message>
- </context>
+</context>
<context>
<name>BanTableModel</name>
<message>
<source>IP/Netmask</source>
- <translation>IP/Ağ maskesi</translation>
+ <translation>IP/Ağ Maskesi</translation>
</message>
<message>
<source>Banned Until</source>
- <translation>Şu vakte kadar yasaklı:</translation>
+ <translation>Şu zamana kadar yasaklı:</translation>
</message>
</context>
<context>
<name>BitcoinGUI</name>
<message>
<source>Sign &amp;message...</source>
- <translation>&amp;Mesaj imzala...</translation>
+ <translation>&amp;İleti imzala...</translation>
</message>
<message>
<source>Synchronizing with network...</source>
- <translation>Şebeke ile senkronizasyon...</translation>
+ <translation>Ağ ile senkronize ediliyor...</translation>
</message>
<message>
<source>&amp;Overview</source>
@@ -187,15 +255,15 @@
</message>
<message>
<source>&amp;Transactions</source>
- <translation>&amp;Muameleler</translation>
+ <translation>&amp;İşlemler</translation>
</message>
<message>
<source>Browse transaction history</source>
- <translation>Muamele tarihçesini tara</translation>
+ <translation>İşlem geçmişine gözat</translation>
</message>
<message>
<source>E&amp;xit</source>
- <translation>&amp;Çık</translation>
+ <translation>Ç&amp;ık</translation>
</message>
<message>
<source>Quit application</source>
@@ -203,7 +271,7 @@
</message>
<message>
<source>&amp;About %1</source>
- <translation>%1 &amp;hakkında</translation>
+ <translation>%1 &amp;Hakkında</translation>
</message>
<message>
<source>Show information about %1</source>
@@ -211,11 +279,11 @@
</message>
<message>
<source>About &amp;Qt</source>
- <translation>&amp;Qt hakkında</translation>
+ <translation>&amp;Qt Hakkında</translation>
</message>
<message>
<source>Show information about Qt</source>
- <translation>Qt hakkında bilgi görüntü</translation>
+ <translation>Qt hakkında bilgi göster</translation>
</message>
<message>
<source>&amp;Options...</source>
@@ -227,15 +295,15 @@
</message>
<message>
<source>&amp;Encrypt Wallet...</source>
- <translation>Cüzdanı &amp;şifrele...</translation>
+ <translation>&amp;Cüzdanı Şifrele...</translation>
</message>
<message>
<source>&amp;Backup Wallet...</source>
- <translation>Cüzdanı &amp;yedekle...</translation>
+ <translation>&amp;Cüzdanı Yedekle...</translation>
</message>
<message>
<source>&amp;Change Passphrase...</source>
- <translation>Parolayı &amp;değiştir...</translation>
+ <translation>&amp;Parolayı Değiştir...</translation>
</message>
<message>
<source>&amp;Sending addresses...</source>
@@ -247,15 +315,31 @@
</message>
<message>
<source>Open &amp;URI...</source>
- <translation>&amp;URI aç...</translation>
+ <translation>&amp;URI Aç...</translation>
+ </message>
+ <message>
+ <source>Click to disable network activity.</source>
+ <translation>Ağ etkinliğini devre dışı bırakmak için tıklayın.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>Ağ etkinliği devre dışı bırakılmış.</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>Ağ etkinliğini yeniden etkinleştirmek için tıklayın.</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>Üstbilgiler Senkronize Ediliyor (%1%)...</translation>
</message>
<message>
<source>Reindexing blocks on disk...</source>
- <translation>Diskteki bloklar yeniden endeksleniyor...</translation>
+ <translation>Diskteki bloklar yeniden indeksleniyor...</translation>
</message>
<message>
<source>Send coins to a Bitcoin address</source>
- <translation>Bir Bitcoin adresine Bitcoin yolla</translation>
+ <translation>Bir bitcoin adresine bitcoin gönder</translation>
</message>
<message>
<source>Backup wallet to another location</source>
@@ -275,7 +359,7 @@
</message>
<message>
<source>&amp;Verify message...</source>
- <translation>Mesaj &amp;kontrol et...</translation>
+ <translation>İletiyi &amp;kontrol et...</translation>
</message>
<message>
<source>Bitcoin</source>
@@ -295,23 +379,23 @@
</message>
<message>
<source>&amp;Show / Hide</source>
- <translation>&amp;Göster / Sakla</translation>
+ <translation>&amp;Göster / Gizle</translation>
</message>
<message>
<source>Show or hide the main Window</source>
- <translation>Ana pencereyi görüntüle ya da sakla</translation>
+ <translation>Ana pencereyi göster ya da gizle</translation>
</message>
<message>
<source>Encrypt the private keys that belong to your wallet</source>
- <translation>Cüzdanınızın özel anahtarlarını şifrele</translation>
+ <translation>Cüzdanınıza ait özel anahtarları şifreleyin</translation>
</message>
<message>
<source>Sign messages with your Bitcoin addresses to prove you own them</source>
- <translation>Mesajları adreslerin size ait olduğunu ispatlamak için Bitcoin adresleri ile imzala</translation>
+ <translation>İletileri adreslerin size ait olduğunu ispatlamak için Bitcoin adresleri ile imzala</translation>
</message>
<message>
<source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
- <translation>Belirtilen Bitcoin adresleri ile imzalandıklarından emin olmak için mesajları kontrol et</translation>
+ <translation>Belirtilen Bitcoin adresleri ile imzalandıklarından emin olmak için iletileri kontrol et</translation>
</message>
<message>
<source>&amp;File</source>
@@ -351,7 +435,7 @@
</message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network</source>
- <translation><numerusform>Bitcoin şebekesine %n faal bağlantı</numerusform><numerusform>Bitcoin şebekesine %n faal bağlantı</numerusform></translation>
+ <translation><numerusform>Bitcoin şebekesine %n faal bağlantı</numerusform><numerusform>Bitcoin ağına %n etkin bağlantı var</numerusform></translation>
</message>
<message>
<source>Indexing blocks on disk...</source>
@@ -359,15 +443,11 @@
</message>
<message>
<source>Processing blocks on disk...</source>
- <translation>Bloklar diske yazıdırılıyor...</translation>
- </message>
- <message>
- <source>No block source available...</source>
- <translation>Hiçbir blok kaynağı mevcut değil...</translation>
+ <translation>Bloklar diske işleniyor...</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>
+ <translation><numerusform>Muamele tarihçesinden %n blok işlendi.</numerusform><numerusform>İşlem tarihçesinden %n blok işlendi</numerusform></translation>
</message>
<message>
<source>%1 behind</source>
@@ -375,11 +455,11 @@
</message>
<message>
<source>Last received block was generated %1 ago.</source>
- <translation>Son alınan blok %1 evvel oluşturulmuştu.</translation>
+ <translation>Son alınan blok %1 önce oluşturulmuştu.</translation>
</message>
<message>
<source>Transactions after this will not yet be visible.</source>
- <translation>Bundan sonraki muameleler henüz görüntülenemez.</translation>
+ <translation>Bundan sonraki işlemler henüz görüntülenemez.</translation>
</message>
<message>
<source>Error</source>
@@ -403,7 +483,11 @@
</message>
<message>
<source>%1 client</source>
- <translation>%1 istemcisi</translation>
+ <translation>%1 istemci</translation>
+ </message>
+ <message>
+ <source>Connecting to peers...</source>
+ <translation>Eşlere bağlanılıyor...</translation>
</message>
<message>
<source>Catching up...</source>
@@ -418,7 +502,7 @@
<message>
<source>Amount: %1
</source>
- <translation>Meblağ: %1
+ <translation>Tutar: %1
</translation>
</message>
<message>
@@ -441,11 +525,19 @@
</message>
<message>
<source>Sent transaction</source>
- <translation>Muamele yollandı</translation>
+ <translation>İşlem gönderildi</translation>
</message>
<message>
<source>Incoming transaction</source>
- <translation>Gelen muamele</translation>
+ <translation>Gelen işlem</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation>HD anahtar oluşturma &lt;b&gt;etkin&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation>HD anahtar oluşturma &lt;b&gt;devre dışı&lt;/b&gt;</translation>
</message>
<message>
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
@@ -455,7 +547,11 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Cüzdan &lt;b&gt;şifrelenmiştir&lt;/b&gt; ve şu anda &lt;b&gt;kilitlidir&lt;/b&gt;</translation>
</message>
- </context>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>Ölümcül bir hata oluştu. Bitcoin yazılımı artık güvenli bir şekilde çalışmaya devam edemediği için kapatılacaktır.</translation>
+ </message>
+</context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -472,7 +568,7 @@
</message>
<message>
<source>Amount:</source>
- <translation>Meblağ:</translation>
+ <translation>Tutar:</translation>
</message>
<message>
<source>Fee:</source>
@@ -504,7 +600,7 @@
</message>
<message>
<source>Amount</source>
- <translation>Meblağ</translation>
+ <translation>Tutar</translation>
</message>
<message>
<source>Received with label</source>
@@ -536,13 +632,77 @@
</message>
<message>
<source>Copy amount</source>
+ <translation>Tutarı kopyala</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>İşlem ID'sini kopyala</translation>
+ </message>
+ <message>
+ <source>Lock unspent</source>
+ <translation>Harcanmamışı kilitle</translation>
+ </message>
+ <message>
+ <source>Unlock unspent</source>
+ <translation>Harcanmamışın kilidini aç</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
<translation>Miktarı kopyala</translation>
</message>
<message>
+ <source>Copy fee</source>
+ <translation>Ücreti kopyala</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Ücretten sonrasını kopyala</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Baytları kopyala</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Tozu kopyala</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Para üstünü kopyala</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation>(%1 kilitlendi)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>evet</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>hayır</translation>
+ </message>
+ <message>
+ <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
+ <translation>Eğer herhangi bir alıcı mevcut toz eşiğinden daha düşük bir tutar alırsa bu etiket kırmızıya dönüşür.</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation>Girdi başına +/- %1 satoshi değişebilir.</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(etiket yok)</translation>
</message>
- </context>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation>%1 ögesinden para üstü (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(para üstü)</translation>
+ </message>
+</context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -565,7 +725,39 @@
<source>&amp;Address</source>
<translation>&amp;Adres</translation>
</message>
- </context>
+ <message>
+ <source>New receiving address</source>
+ <translation>Yeni alım adresi</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Yeni gönderi adresi</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Alım adresini düzenle</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Gönderi adresini düzenle</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>Girilen "%1" adresi geçerli bir Bitcoin adresi değildir.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book.</source>
+ <translation>Girilen "%1" adresi zaten adres defterinde mevcuttur.</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Cüzdan kilidi açılamadı.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Yeni anahtar oluşturulması başarısız oldu.</translation>
+ </message>
+</context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -578,7 +770,7 @@
</message>
<message>
<source>Directory already exists. Add %1 if you intend to create a new directory here.</source>
- <translation>Klasör hâlihazırda mevcuttur. Burada yeni bir klasör oluşturmak istiyorsanız, %1 ilâve ediniz.</translation>
+ <translation>Klasör zaten mevcuttur. Burada yeni bir klasör oluşturmak istiyorsanız, %1 ekleyiniz.</translation>
</message>
<message>
<source>Path already exists, and is not a directory.</source>
@@ -660,7 +852,7 @@
</message>
<message>
<source>%1 will download and store a copy of the Bitcoin block chain. At least %2GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory.</source>
- <translation>%1, Bitcoin blok zincirinin bir kopyasını indirecek ve saklayacaktır. Bu klasörde en az %2GB veri saklanacak ve bu zamanla artacaktır. Cüzdan da bu klasörde saklanacaktır.</translation>
+ <translation>%1, Bitcoin blok zincirinin bir kopyasını indirecek ve saklayacaktır. Bu klasörde en az %2 GB veri saklanacak ve bu zamanla artacaktır. Cüzdan da bu klasörde saklanacaktır.</translation>
</message>
<message>
<source>Use the default data directory</source>
@@ -694,19 +886,55 @@
<translation>Form</translation>
</message>
<message>
+ <source>Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source>
+ <translation>Son işlemler henüz görünmeyebilir ve bu nedenle cüzdanınızın bakiyesi yanlış olabilir. Bu bilgiler, aşağıda detaylandırıldığı gibi, cüzdanınız bitcoin ağı ile senkronizasyonunu tamamladığında doğru olacaktır. </translation>
+ </message>
+ <message>
+ <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source>
+ <translation>Henüz görüntülenmeyen işlemlerden etkilenen bitcoinleri harcama girişiminde bulunmak ağ tarafından kabul edilmeyecektir.</translation>
+ </message>
+ <message>
+ <source>Number of blocks left</source>
+ <translation>Kalan blok sayısı</translation>
+ </message>
+ <message>
+ <source>Unknown...</source>
+ <translation>Bilinmiyor...</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation>Son blok zamanı</translation>
</message>
<message>
+ <source>Progress</source>
+ <translation>İlerleme</translation>
+ </message>
+ <message>
+ <source>Progress increase per hour</source>
+ <translation>Saat başı ilerleme artışı</translation>
+ </message>
+ <message>
+ <source>calculating...</source>
+ <translation>hesaplanıyor...</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation>Senkronize edilene kadar kalan tahmini süre</translation>
+ </message>
+ <message>
<source>Hide</source>
- <translation>Sakla</translation>
+ <translation>Gizle</translation>
</message>
- </context>
+ <message>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation>Bilinmeyen. Üstbilgiler Senkronize Ediliyor (%1)...</translation>
+ </message>
+</context>
<context>
<name>OpenURIDialog</name>
<message>
<source>Open URI</source>
- <translation>URI aç</translation>
+ <translation>URI Aç</translation>
</message>
<message>
<source>Open payment request from URI or file</source>
@@ -720,7 +948,11 @@
<source>Select payment request file</source>
<translation>Ödeme talebi dosyasını seç</translation>
</message>
- </context>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>Açılacak ödeme talebi dosyasını seç</translation>
+ </message>
+</context>
<context>
<name>OptionsDialog</name>
<message>
@@ -729,7 +961,7 @@
</message>
<message>
<source>&amp;Main</source>
- <translation>&amp;Esas ayarlar</translation>
+ <translation>&amp;Genel</translation>
</message>
<message>
<source>Automatically start %1 after logging in to the system.</source>
@@ -741,7 +973,7 @@
</message>
<message>
<source>Size of &amp;database cache</source>
- <translation>&amp;Veritabanı tamponunun boyutu</translation>
+ <translation>&amp;Veritabanı önbelleğinin boyutu</translation>
</message>
<message>
<source>MB</source>
@@ -769,15 +1001,15 @@
</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>
+ <translation>İşlemler sekmesinde bağlam menüsü unsurları olarak görünen üçüncü taraf bağlantıları (mesela bir blok tarayıcısı). URL'deki %s, işlem hash değeri ile değiştirilecektir. Birden çok bağlantılar düşey çubuklar | ile ayrılacaktır.</translation>
</message>
<message>
<source>Third party transaction URLs</source>
- <translation>Üçüncü taraf muamele URL'leri</translation>
+ <translation>Üçüncü parti işlem URL'leri</translation>
</message>
<message>
<source>Active command-line options that override above options:</source>
- <translation>Yukarıdaki seçeneklerin yerine geçen faal komut satırı seçenekleri:</translation>
+ <translation>Yukarıdaki seçeneklerin yerine geçen etkin komut satırı seçenekleri:</translation>
</message>
<message>
<source>Reset all client options to default.</source>
@@ -785,11 +1017,11 @@
</message>
<message>
<source>&amp;Reset Options</source>
- <translation>Seçenekleri Sıfı&amp;rla</translation>
+ <translation>Seçenekleri &amp;Sıfırla</translation>
</message>
<message>
<source>&amp;Network</source>
- <translation>&amp;Şebeke</translation>
+ <translation>&amp;Ağ</translation>
</message>
<message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
@@ -809,11 +1041,11 @@
</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>Teyit edilmemiş para üstünü harcamayı devre dışı bırakırsanız, bir muamelenin para üstü bu muamele için en az bir teyit olana dek harcanamaz. Bu, aynı zamanda bakiyenizin nasıl hesaplandığını da etkiler.</translation>
+ <translation>Doğrulanmamış para üstünü harcamayı devre dışı bırakırsanız, bir işlemin para üstü bu işlem için en az bir doğrulama olana dek harcanamaz. Bu, aynı zamanda bakiyenizin nasıl hesaplandığını da etkiler.</translation>
</message>
<message>
<source>&amp;Spend unconfirmed change</source>
- <translation>Teyit edilmemiş para üstünü &amp;harca</translation>
+ <translation>Doğrulanmamış para üstünü &amp;harca</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>
@@ -825,15 +1057,15 @@
</message>
<message>
<source>Connect to the Bitcoin network through a SOCKS5 proxy.</source>
- <translation>Bitcoin şebekesine SOCKS5 vekil sunucusu vasıtasıyla bağlan.</translation>
+ <translation>Bitcoin ağına bir SOCKS5 vekil sunucusu aracılığıyla bağlan.</translation>
</message>
<message>
<source>&amp;Connect through SOCKS5 proxy (default proxy):</source>
- <translation>SOCKS5 vekil sunucusu vasıtasıyla &amp;bağlan (varsayılan vekil sunucusu):</translation>
+ <translation>SOCKS5 vekil sunucusu aracılığıyla &amp;bağlan (varsayılan vekil sunucusu):</translation>
</message>
<message>
<source>Proxy &amp;IP:</source>
- <translation>Vekil &amp;İP:</translation>
+ <translation>Vekil &amp;IP:</translation>
</message>
<message>
<source>&amp;Port:</source>
@@ -845,11 +1077,11 @@
</message>
<message>
<source>Used for reaching peers via:</source>
- <translation>Eşlere ulaşmak için kullanılır, şu yoluyla:</translation>
+ <translation>Eşlere ulaşmak için kullanılır, şu üzerinden:</translation>
</message>
<message>
<source>Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source>
- <translation>Bu şebeke türü yoluyla eşlere bağlanmak için belirtilen varsayılan SOCKS5 vekil sunucusunun kullanılıp kullanılmadığını gösterir.</translation>
+ <translation>Bu ağ türü yoluyla eşlere bağlanmak için belirtilen varsayılan SOCKS5 vekil sunucusunun kullanılıp kullanılmadığını gösterir.</translation>
</message>
<message>
<source>IPv4</source>
@@ -865,7 +1097,7 @@
</message>
<message>
<source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source>
- <translation>Bitcoin şebekesine gizli Tor servisleri için ayrı bir SOCKS5 vekil sunucusu vasıtasıyla bağlan.</translation>
+ <translation>Bitcoin ağına gizli Tor servisleri için ayrı bir SOCKS5 vekil sunucusu aracılığıyla bağlan.</translation>
</message>
<message>
<source>Use separate SOCKS5 proxy to reach peers via Tor hidden services:</source>
@@ -877,15 +1109,15 @@
</message>
<message>
<source>&amp;Hide the icon from the system tray.</source>
- <translation>İkonu sistem çekmecesinden &amp;sakla</translation>
+ <translation>Simgeyi görev çubuğundan &amp;gizle</translation>
</message>
<message>
<source>Hide tray icon</source>
- <translation>Sistem çekmecesi ikonunu sakla</translation>
+ <translation>Görev çubuğu simgesini gizle</translation>
</message>
<message>
<source>Show only a tray icon after minimizing the window.</source>
- <translation>Küçültüldükten sonra sadece çekmece ikonu göster.</translation>
+ <translation>Küçültüldükten sonra sadece tepsi simgesi göster.</translation>
</message>
<message>
<source>&amp;Minimize to the tray instead of the taskbar</source>
@@ -909,7 +1141,7 @@
</message>
<message>
<source>&amp;Unit to show amounts in:</source>
- <translation>Meblağları göstermek için &amp;birim:</translation>
+ <translation>Tutarı göstermek için &amp;birim:</translation>
</message>
<message>
<source>Choose the default subdivision unit to show in the interface and when sending coins.</source>
@@ -964,7 +1196,7 @@
</message>
<message>
<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>Görüntülenen veriler zaman aşımına uğramış olabilir. Bağlantı kurulduğunda cüzdanınız otomatik olarak şebeke ile eşleşir ancak bu işlem henüz tamamlanmamıştır.</translation>
+ <translation>Görüntülenen bilgiler güncel olmayabilir. Bağlantı kurulduğunda cüzdanınız otomatik olarak Bitcoin ağı ile senkronize olur ancak bu işlem henüz tamamlanmamıştır.</translation>
</message>
<message>
<source>Watch-only:</source>
@@ -984,7 +1216,7 @@
</message>
<message>
<source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source>
- <translation>Henüz teyit edilmemiş ve harcanabilir bakiyeye eklenmemiş muamelelerin toplamı</translation>
+ <translation>Henüz doğrulanmamış ve harcanabilir bakiyeye eklenmemiş işlemlerin toplamı</translation>
</message>
<message>
<source>Immature:</source>
@@ -1016,11 +1248,11 @@
</message>
<message>
<source>Recent transactions</source>
- <translation>Son muameleler</translation>
+ <translation>Son işlemler</translation>
</message>
<message>
<source>Unconfirmed transactions to watch-only addresses</source>
- <translation>Sadece izlenen adreslere gelen teyit edilmemiş muameleler</translation>
+ <translation>Sadece izlenen adreslere gelen doğrulanmamış işlemler</translation>
</message>
<message>
<source>Mined balance in watch-only addresses that has not yet matured</source>
@@ -1033,7 +1265,95 @@
</context>
<context>
<name>PaymentServer</name>
- </context>
+ <message>
+ <source>Payment request error</source>
+ <translation>Ödeme talebi hatası</translation>
+ </message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation>Bitcoin başlatılamadı: tıkla-ve-öde yöneticisi</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation>URI yönetimi</translation>
+ </message>
+ <message>
+ <source>Payment request fetch URL is invalid: %1</source>
+ <translation>Ödeme talebini alma URL'i geçersiz: %1</translation>
+ </message>
+ <message>
+ <source>Invalid payment address %1</source>
+ <translation>%1 ödeme adresi geçersizdir</translation>
+ </message>
+ <message>
+ <source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
+ <translation>URI ayrıştırılamıyor! Bunun nedeni geçersiz bir Bitcoin adresi veya hatalı biçimlendirilmiş URI değişkenleri olabilir.</translation>
+ </message>
+ <message>
+ <source>Payment request file handling</source>
+ <translation>Ödeme talebi dosyası yönetimi</translation>
+ </message>
+ <message>
+ <source>Payment request file cannot be read! This can be caused by an invalid payment request file.</source>
+ <translation>Ödeme talebi dosyası okunamıyor! Bunun nedeni geçersiz bir ödeme talebi dosyası olabilir.</translation>
+ </message>
+ <message>
+ <source>Payment request rejected</source>
+ <translation>Ödeme talebi reddedildi</translation>
+ </message>
+ <message>
+ <source>Payment request network doesn't match client network.</source>
+ <translation>Ödeme talebi ağı, istemci ağıyla eşleşmiyor.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Ödeme talebinin geçerlilik süresi bitti.</translation>
+ </message>
+ <message>
+ <source>Payment request is not initialized.</source>
+ <translation>Ödeme talebi başlatılmadı.</translation>
+ </message>
+ <message>
+ <source>Unverified payment requests to custom payment scripts are unsupported.</source>
+ <translation>Özel ödeme betiklerine, doğrulanmamış ödeme talepleri desteklenmez.</translation>
+ </message>
+ <message>
+ <source>Invalid payment request.</source>
+ <translation>Geçersiz ödeme talebi.</translation>
+ </message>
+ <message>
+ <source>Requested payment amount of %1 is too small (considered dust).</source>
+ <translation>Talep edilen %1 ödeme tutarı çok küçüktür (toz olarak kabul edilir).</translation>
+ </message>
+ <message>
+ <source>Refund from %1</source>
+ <translation>%1 adresinden geri ödeme</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, üst sınır %3 bayt).</translation>
+ </message>
+ <message>
+ <source>Error communicating with %1: %2</source>
+ <translation>%1 ile iletişimde hata: %2</translation>
+ </message>
+ <message>
+ <source>Payment request cannot be parsed!</source>
+ <translation>Ödeme talebi ayrıştırılamaz!</translation>
+ </message>
+ <message>
+ <source>Bad response from server %1</source>
+ <translation>%1 sunucusundan hatalı yanıt</translation>
+ </message>
+ <message>
+ <source>Network request error</source>
+ <translation>Ağ talebi hatası</translation>
+ </message>
+ <message>
+ <source>Payment acknowledged</source>
+ <translation>Ödeme kabul edildi</translation>
+ </message>
+</context>
<context>
<name>PeerTableModel</name>
<message>
@@ -1044,12 +1364,20 @@
<source>Node/Service</source>
<translation>Düğüm/Servis</translation>
</message>
- </context>
+ <message>
+ <source>NodeId</source>
+ <translation>Düğüm ID'si</translation>
+ </message>
+ <message>
+ <source>Ping</source>
+ <translation>Ping</translation>
+ </message>
+</context>
<context>
<name>QObject</name>
<message>
<source>Amount</source>
- <translation>Meblağ</translation>
+ <translation>Tutar</translation>
</message>
<message>
<source>Enter a Bitcoin address (e.g. %1)</source>
@@ -1083,21 +1411,73 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation><numerusform>%n saniye</numerusform><numerusform>%n saniye</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation><numerusform>%n dakika</numerusform><numerusform>%n dakika</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation><numerusform>%n saat</numerusform><numerusform>%n saat</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation><numerusform>%n gün</numerusform><numerusform>%n gün</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation><numerusform>%n hafta</numerusform><numerusform>%n hafta</numerusform></translation>
+ </message>
<message>
<source>%1 and %2</source>
<translation>%1 ve %2</translation>
</message>
- </context>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation><numerusform>%n yıl</numerusform><numerusform>%n yıl</numerusform></translation>
+ </message>
+ <message>
+ <source>%1 didn't yet exit safely...</source>
+ <translation>%1 henüz güvenli bir şekilde çıkış yapmamıştır...</translation>
+ </message>
+</context>
<context>
<name>QObject::QObject</name>
- </context>
+ <message>
+ <source>Error: Specified data directory "%1" does not exist.</source>
+ <translation>Hata: Belirtilen "%1" veri klasörü yoktur.</translation>
+ </message>
+ <message>
+ <source>Error: Cannot parse configuration file: %1. Only use key=value syntax.</source>
+ <translation>Hata: %1 yapılandırma dosyası ayrıştırılamadı. Sadece anahtar=değer dizimini kullanınız.</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation>Hata: %1</translation>
+ </message>
+</context>
<context>
<name>QRImageWidget</name>
<message>
<source>&amp;Save Image...</source>
<translation>Resmi ka&amp;ydet...</translation>
</message>
- </context>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>Resmi &amp;Kopyala</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>QR Kodu Kaydet</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>PNG Resim (*.png)</translation>
+ </message>
+</context>
<context>
<name>RPCConsole</name>
<message>
@@ -1110,7 +1490,7 @@
</message>
<message>
<source>&amp;Information</source>
- <translation>&amp;Malumat</translation>
+ <translation>&amp;Bilgi</translation>
</message>
<message>
<source>Debug window</source>
@@ -1134,7 +1514,7 @@
</message>
<message>
<source>Network</source>
- <translation>Şebeke</translation>
+ <translation>Ağ</translation>
</message>
<message>
<source>Name</source>
@@ -1158,7 +1538,7 @@
</message>
<message>
<source>Current number of transactions</source>
- <translation>Güncel muamele sayısı</translation>
+ <translation>Güncel işlem sayısı</translation>
</message>
<message>
<source>Memory usage</source>
@@ -1202,7 +1582,7 @@
</message>
<message>
<source>Synced Headers</source>
- <translation>Eşleşmiş Başlıklar</translation>
+ <translation>Eşleşmiş Üstbilgiler</translation>
</message>
<message>
<source>Synced Blocks</source>
@@ -1257,6 +1637,10 @@
<translation>Ping Beklemesi</translation>
</message>
<message>
+ <source>Min Ping</source>
+ <translation>En Düşük Ping</translation>
+ </message>
+ <message>
<source>Time Offset</source>
<translation>Saat Farkı</translation>
</message>
@@ -1274,7 +1658,7 @@
</message>
<message>
<source>&amp;Network Traffic</source>
- <translation>&amp;Şebeke trafiği</translation>
+ <translation>&amp;Ağ trafiği</translation>
</message>
<message>
<source>&amp;Clear</source>
@@ -1317,18 +1701,38 @@
<translation>1 &amp;yıl</translation>
</message>
<message>
+ <source>&amp;Disconnect</source>
+ <translation>&amp;Bağlantıyı Kes</translation>
+ </message>
+ <message>
+ <source>Ban for</source>
+ <translation>Yasakla</translation>
+ </message>
+ <message>
+ <source>&amp;Unban</source>
+ <translation>&amp;Yasaklamayı Kaldır</translation>
+ </message>
+ <message>
<source>Welcome to the %1 RPC console.</source>
<translation>%1 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>
+ <translation>Tarihçede gezinmek için aşağı ve yukarı ok tuşlarını kullanınız, &lt;b&gt;Ctrl-L&lt;/b&gt; ile de ekranı temizleyebilirsiniz.</translation>
</message>
<message>
<source>Type &lt;b&gt;help&lt;/b&gt; for an overview of available commands.</source>
<translation>Mevcut komutların listesi için &lt;b&gt;help&lt;/b&gt; yazınız.</translation>
</message>
<message>
+ <source>WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramification of a command.</source>
+ <translation>UYARI: Bitcoin dolandırıcılarının çok fazla etkin olduğu zamanlarda, dolandırıcılar bazı kullanıcılara buraya komutlar yazmalarını söylerek onların cüzdanlarındaki bitcoinleri çalmışlardır. Bir komutun sonuçlarını tam olarak anlamadan bu konsolu kullanmayın.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled</source>
+ <translation>Ağ etkinliği devre dışı bırakıldı</translation>
+ </message>
+ <message>
<source>%1 B</source>
<translation>%1 B</translation>
</message>
@@ -1381,7 +1785,7 @@
<name>ReceiveCoinsDialog</name>
<message>
<source>&amp;Amount:</source>
- <translation>&amp;Meblağ:</translation>
+ <translation>&amp;Tutar:</translation>
</message>
<message>
<source>&amp;Label:</source>
@@ -1389,7 +1793,7 @@
</message>
<message>
<source>&amp;Message:</source>
- <translation>Me&amp;saj:</translation>
+ <translation>&amp;İleti:</translation>
</message>
<message>
<source>Reuse one of the previously used receiving addresses. Reusing addresses has security and privacy issues. Do not use this unless re-generating a payment request made before.</source>
@@ -1401,7 +1805,7 @@
</message>
<message>
<source>An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Bitcoin network.</source>
- <translation>Talep açıldığında gösterilecek, isteğinize dayalı, ödeme talebi ile ilişkilendirilecek bir mesaj. Not: Bu mesaj ödeme ile birlikte Bitcoin şebekesi üzerinden gönderilmeyecektir.</translation>
+ <translation>Talep açıldığında gösterilecek, isteğinize dayalı, ödeme talebi ile ilişkilendirilecek bir ileti. Not: Bu ileti ödeme ile birlikte Bitcoin ağı üzerinden gönderilmeyecektir.</translation>
</message>
<message>
<source>An optional label to associate with the new receiving address.</source>
@@ -1413,7 +1817,7 @@
</message>
<message>
<source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source>
- <translation>Seçiminize dayalı talep edilecek meblağ. Belli bir meblağ talep etmemek için bunu boş bırakın veya sıfır değerini kullanın.</translation>
+ <translation>Seçiminize dayalı talep edilecek tutar. Belli bir tutar talep etmemek için bunu boş bırakın veya sıfır değerini kullanın.</translation>
</message>
<message>
<source>Clear all fields of the form.</source>
@@ -1448,12 +1852,20 @@
<translation>Kaldır</translation>
</message>
<message>
+ <source>Copy URI</source>
+ <translation>URI'yi kopyala</translation>
+ </message>
+ <message>
<source>Copy label</source>
<translation>Etiket kopyala</translation>
</message>
<message>
+ <source>Copy message</source>
+ <translation>İletiyi kopyala</translation>
+ </message>
+ <message>
<source>Copy amount</source>
- <translation>Miktarı kopyala</translation>
+ <translation>Tutarı kopyala</translation>
</message>
</context>
<context>
@@ -1475,25 +1887,73 @@
<translation>Resmi ka&amp;ydet...</translation>
</message>
<message>
+ <source>Request payment to %1</source>
+ <translation>%1 unsuruna ödeme talep et</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>Ödeme bilgisi</translation>
+ </message>
+ <message>
+ <source>URI</source>
+ <translation>URI</translation>
+ </message>
+ <message>
<source>Address</source>
<translation>Adres</translation>
</message>
<message>
+ <source>Amount</source>
+ <translation>Tutar</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>Etiket</translation>
</message>
- </context>
+ <message>
+ <source>Message</source>
+ <translation>İleti</translation>
+ </message>
+ <message>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation>Sonuç URI çok uzun, etiket ya da ileti metnini kısaltmayı deneyiniz.</translation>
+ </message>
+ <message>
+ <source>Error encoding URI into QR Code.</source>
+ <translation>URI'nin QR koduna kodlanmasında hata oluştu.</translation>
+ </message>
+</context>
<context>
<name>RecentRequestsTableModel</name>
<message>
+ <source>Date</source>
+ <translation>Tarih</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>Etiket</translation>
</message>
<message>
+ <source>Message</source>
+ <translation>İleti</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(etiket yok)</translation>
</message>
- </context>
+ <message>
+ <source>(no message)</source>
+ <translation>(ileti yok)</translation>
+ </message>
+ <message>
+ <source>(no amount requested)</source>
+ <translation>(tutar talep edilmedi)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation>Talep edilen</translation>
+ </message>
+</context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1526,7 +1986,7 @@
</message>
<message>
<source>Amount:</source>
- <translation>Meblağ:</translation>
+ <translation>Tutar:</translation>
</message>
<message>
<source>Fee:</source>
@@ -1550,7 +2010,7 @@
</message>
<message>
<source>Transaction Fee:</source>
- <translation>Muamele ücreti:</translation>
+ <translation>İşlem ücreti:</translation>
</message>
<message>
<source>Choose...</source>
@@ -1566,11 +2026,11 @@
</message>
<message>
<source>If the custom fee is set to 1000 satoshis and the transaction is only 250 bytes, then "per kilobyte" only pays 250 satoshis in fee, while "total at least" pays 1000 satoshis. For transactions bigger than a kilobyte both pay by kilobyte.</source>
- <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>
+ <translation>Eğer özel ücret 1000 satoşi olarak ayarlandıysa ve işlem sadece 250 baytsa, "kilobayt başı" ücret olarak sadece 250 satoşi öder ve "toplam asgari" 1000 satoşi öder. Bir kilobayttan yüksek işlemler için ikisi de kilobayt başı ödeme yapar.</translation>
</message>
<message>
<source>Hide</source>
- <translation>Sakla</translation>
+ <translation>Gizle</translation>
</message>
<message>
<source>total at least</source>
@@ -1578,7 +2038,7 @@
</message>
<message>
<source>Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks. But be aware that this can end up in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source>
- <translation>Asgari ücreti ödemek, bloklarda boşluktan daha az muamele hacmi olduğu sürece bir sorun çıkarmaz. Fakat şebekenin işleyecebileceğinden daha çok bitcoin muameleleri talebi olduğunda bunun asla teyit edilmeyen bir muamele olabileceğinin farkında olmalısınız.</translation>
+ <translation>Gerekli olan en az ücreti ödemek, bloklarda boşluktan daha az işlem hacmi olduğu sürece bir sorun çıkarmaz. Fakat ağın işleyecebileceğinden daha çok bitcoin işlemi talebi olduğunda bunun asla doğrulanmayan bir işlem olabileceğinin farkında olmalısınız.</translation>
</message>
<message>
<source>(read the tooltip)</source>
@@ -1621,6 +2081,10 @@
<translation>Toz:</translation>
</message>
<message>
+ <source>Confirmation time target:</source>
+ <translation>Doğrulama süresi hedefi:</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>Tümünü &amp;temizle</translation>
</message>
@@ -1637,10 +2101,118 @@
<translation>G&amp;önder</translation>
</message>
<message>
- <source>Copy amount</source>
+ <source>Copy quantity</source>
<translation>Miktarı kopyala</translation>
</message>
<message>
+ <source>Copy amount</source>
+ <translation>Tutarı kopyala</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Ücreti kopyala</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Ücretten sonrasını kopyala</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Baytları kopyala</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Tozu kopyala</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Para üstünü kopyala</translation>
+ </message>
+ <message>
+ <source>%1 to %2</source>
+ <translation>%1 ögesinden %2 unsuruna</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to send?</source>
+ <translation>Göndermek istediğinizden emin misiniz?</translation>
+ </message>
+ <message>
+ <source>added as transaction fee</source>
+ <translation>işlem ücreti olarak eklendi</translation>
+ </message>
+ <message>
+ <source>Total Amount %1</source>
+ <translation>Toplam Tutar %1</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>veya</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation>Bitcoin gönderimini onaylayın</translation>
+ </message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>Alıcı adresi geçerli değildir. Lütfen tekrar kontrol ediniz.</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation>Ödeyeceğiniz tutarın 0'dan yüksek olması gerekir.</translation>
+ </message>
+ <message>
+ <source>The amount exceeds your balance.</source>
+ <translation>Tutar bakiyenizden yüksektir.</translation>
+ </message>
+ <message>
+ <source>The total exceeds your balance when the %1 transaction fee is included.</source>
+ <translation>Toplam, %1 işlem ücreti eklendiğinde bakiyenizi geçmektedir.</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation>Tekrarlayan adres bulundu: adresler sadece bir kez kullanılmalıdır.</translation>
+ </message>
+ <message>
+ <source>Transaction creation failed!</source>
+ <translation>İşlem oluşturma başarısız!</translation>
+ </message>
+ <message>
+ <source>The transaction was rejected with the following reason: %1</source>
+ <translation>İşlem şu nedenden dolayı reddedildi: %1</translation>
+ </message>
+ <message>
+ <source>A fee higher than %1 is considered an absurdly high fee.</source>
+ <translation>%1 tutarından yüksek bir ücret saçma derecede yüksek bir ücret olarak kabul edilir.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Ödeme talebinin geçerlilik süresi bitti.</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n block(s)</source>
+ <translation><numerusform>%n blok</numerusform><numerusform>%n blok</numerusform></translation>
+ </message>
+ <message>
+ <source>Pay only the required fee of %1</source>
+ <translation>Sadece asgari ücret olan %1 tutarını öde</translation>
+ </message>
+ <message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>Uyarı: geçersiz Bitcoin adresi</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <translation>Uyarı: Bilinmeyen para üstü adresi</translation>
+ </message>
+ <message>
+ <source>Confirm custom change address</source>
+ <translation>Özel para üstü adresini onayla</translation>
+ </message>
+ <message>
+ <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source>
+ <translation>Para üstü için seçtiğiniz adres bu cüzdanın bir parçası değil. Cüzdanınızdaki bir miktar veya tüm para bu adrese gönderilebilir. Emin misiniz?</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(etiket yok)</translation>
</message>
@@ -1649,7 +2221,7 @@
<name>SendCoinsEntry</name>
<message>
<source>A&amp;mount:</source>
- <translation>Mebla&amp;ğ:</translation>
+ <translation>T&amp;utar:</translation>
</message>
<message>
<source>Pay &amp;To:</source>
@@ -1685,19 +2257,19 @@
</message>
<message>
<source>Remove this entry</source>
- <translation>Bu unsuru kaldır</translation>
+ <translation>Bu ögeyi 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>
+ <translation>Ücret yollanan tutardan alınacaktır. Alıcı tutar alanına 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>
+ <translation>Ücreti tutardan düş</translation>
</message>
<message>
<source>Message:</source>
- <translation>Mesaj:</translation>
+ <translation>İleti:</translation>
</message>
<message>
<source>This is an unauthenticated payment request.</source>
@@ -1713,7 +2285,7 @@
</message>
<message>
<source>A message that was attached to the bitcoin: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Bitcoin network.</source>
- <translation>Bitcoin: URI'siyle ilişkili ve bilginiz için muameleyle saklanacak bir mesaj. Not: Bu mesaj Bitcoin şebekesi üzerinden gönderilmeyecektir.</translation>
+ <translation>Referans için bitcoin: URI'siyle iliştirilmiş işlemle birlikte depolanacak bir ileti. Not: Bu mesaj Bitcoin ağı üzerinden gönderilmeyecektir.</translation>
</message>
<message>
<source>Pay To:</source>
@@ -1723,10 +2295,18 @@
<source>Memo:</source>
<translation>Not:</translation>
</message>
- </context>
+ <message>
+ <source>Enter a label for this address to add it to your address book</source>
+ <translation>Adres defterinize eklemek için bu adrese bir etiket giriniz</translation>
+ </message>
+</context>
<context>
<name>SendConfirmationDialog</name>
- </context>
+ <message>
+ <source>Yes</source>
+ <translation>Evet</translation>
+ </message>
+</context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1742,19 +2322,19 @@
<name>SignVerifyMessageDialog</name>
<message>
<source>Signatures - Sign / Verify a Message</source>
- <translation>İmzalar - Mesaj İmzala / Kontrol et</translation>
+ <translation>İmzalar - İleti İmzala / Kontrol et</translation>
</message>
<message>
<source>&amp;Sign Message</source>
- <translation>Mesaj &amp;imzala</translation>
+ <translation>İleti &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>
+ <translation>Adreslerinize yollanan bitcoinleri alabileceğiniz ispatlamak için adreslerinizle iletiler/anlaşmalar 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>
+ <translation>İletinin imzalanmasında kullanılacak Bitcoin adresi</translation>
</message>
<message>
<source>Choose previously used address</source>
@@ -1774,7 +2354,7 @@
</message>
<message>
<source>Enter the message you want to sign here</source>
- <translation>İmzalamak istediğiniz mesajı burada giriniz</translation>
+ <translation>İmzalamak istediğiniz iletiyi burada giriniz</translation>
</message>
<message>
<source>Signature</source>
@@ -1786,15 +2366,15 @@
</message>
<message>
<source>Sign the message to prove you own this Bitcoin address</source>
- <translation>Bu Bitcoin adresinin sizin olduğunu ispatlamak için mesajı imzalayın</translation>
+ <translation>Bu Bitcoin adresinin sizin olduğunu ispatlamak için iletiyi imzalayın</translation>
</message>
<message>
<source>Sign &amp;Message</source>
- <translation>&amp;Mesajı imzala</translation>
+ <translation>&amp;İletiyi imzala</translation>
</message>
<message>
<source>Reset all sign message fields</source>
- <translation>Tüm mesaj alanlarını sıfırla</translation>
+ <translation>Tüm ileti alanlarını sıfırla</translation>
</message>
<message>
<source>Clear &amp;All</source>
@@ -1802,29 +2382,81 @@
</message>
<message>
<source>&amp;Verify Message</source>
- <translation>Mesaj &amp;kontrol et</translation>
+ <translation>İletiyi &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>
+ <translation>Alıcının adresini, iletiyi (satır sonları, boşluklar, sekmeler vs. karakterleri tam olarak kopyaladığınızdan emin olunuz) ve imzayı aşağıya giriniz. Bir ortadaki adam saldırısı tarafından kandırılmaya engel olmak için imzadan, imzalı iletinin 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 işlemin 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>
+ <translation>İletinin imzalanmasında kullanılan Bitcoin adresi</translation>
</message>
<message>
<source>Verify the message to ensure it was signed with the specified Bitcoin address</source>
- <translation>Belirtilen Bitcoin adresi ile imzalandığını doğrulamak için mesajı kontrol et</translation>
+ <translation>Belirtilen Bitcoin adresi ile imzalandığını doğrulamak için iletiyi kontrol et</translation>
</message>
<message>
<source>Verify &amp;Message</source>
- <translation>&amp;Mesaj kontrol et</translation>
+ <translation>&amp;İletiyi kontrol et</translation>
</message>
<message>
<source>Reset all verify message fields</source>
- <translation>Tüm mesaj kontrolü alanlarını sıfırla</translation>
+ <translation>Tüm ileti kontrolü alanlarını sıfırla</translation>
+ </message>
+ <message>
+ <source>Click "Sign Message" to generate signature</source>
+ <translation>İmzayı oluşturmak için "İletiyi İmzala"ya tıklayın</translation>
+ </message>
+ <message>
+ <source>The entered address is invalid.</source>
+ <translation>Girilen adres geçersizdir.</translation>
+ </message>
+ <message>
+ <source>Please check the address and try again.</source>
+ <translation>Lütfen adresi kontrol edip tekrar deneyiniz.</translation>
+ </message>
+ <message>
+ <source>The entered address does not refer to a key.</source>
+ <translation>Girilen adres herhangi bir anahtara işaret etmemektedir.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock was cancelled.</source>
+ <translation>Cüzdan kilidinin açılması iptal edildi.</translation>
+ </message>
+ <message>
+ <source>Private key for the entered address is not available.</source>
+ <translation>Girilen adres için özel anahtar mevcut değildir.</translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation>İleti imzalaması başarısız oldu.</translation>
+ </message>
+ <message>
+ <source>Message signed.</source>
+ <translation>İleti imzalandı.</translation>
+ </message>
+ <message>
+ <source>The signature could not be decoded.</source>
+ <translation>İmzanın kodu çözülemedi.</translation>
</message>
- </context>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation>Lütfen imzayı kontrol edip tekrar deneyiniz.</translation>
+ </message>
+ <message>
+ <source>The signature did not match the message digest.</source>
+ <translation>İmza iletinin özeti ile eşleşmedi.</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation>İleti doğrulaması başarısız oldu.</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation>İleti doğrulandı.</translation>
+ </message>
+</context>
<context>
<name>SplashScreen</name>
<message>
@@ -1841,28 +2473,368 @@
</context>
<context>
<name>TransactionDesc</name>
- </context>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>%n taneden daha fazla blok için açık</numerusform><numerusform>%n taneden daha fazla blok için açık</numerusform></translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>%1 değerine dek açık</translation>
+ </message>
+ <message>
+ <source>conflicted with a transaction with %1 confirmations</source>
+ <translation>%1 doğrulamalı bir işlem ile çelişti</translation>
+ </message>
+ <message>
+ <source>%1/offline</source>
+ <translation>%1/çevrim dışı</translation>
+ </message>
+ <message>
+ <source>0/unconfirmed, %1</source>
+ <translation>0/doğrulanmamış, %1</translation>
+ </message>
+ <message>
+ <source>in memory pool</source>
+ <translation>bellek alanında</translation>
+ </message>
+ <message>
+ <source>not in memory pool</source>
+ <translation>bellek alanında değil</translation>
+ </message>
+ <message>
+ <source>abandoned</source>
+ <translation>terk edilmiş</translation>
+ </message>
+ <message>
+ <source>%1/unconfirmed</source>
+ <translation>%1/doğrulanmadı</translation>
+ </message>
+ <message>
+ <source>%1 confirmations</source>
+ <translation>%1 doğrulama</translation>
+ </message>
+ <message>
+ <source>Status</source>
+ <translation>Durum</translation>
+ </message>
+ <message>
+ <source>, has not been successfully broadcast yet</source>
+ <translation>, henüz başarılı bir şekilde yayınlanmadı</translation>
+ </message>
+ <message numerus="yes">
+ <source>, broadcast through %n node(s)</source>
+ <translation><numerusform>, %n düğüm aracılığıyla yayınlandı</numerusform><numerusform>, %n düğüm aracılığıyla yayınlandı</numerusform></translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Tarih</translation>
+ </message>
+ <message>
+ <source>Source</source>
+ <translation>Kaynak</translation>
+ </message>
+ <message>
+ <source>Generated</source>
+ <translation>Oluşturuldu</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>Gönderen</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>bilinmiyor</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation>Alıcı</translation>
+ </message>
+ <message>
+ <source>own address</source>
+ <translation>kendi adresiniz</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>sadece-izlenen</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>etiket</translation>
+ </message>
+ <message>
+ <source>Credit</source>
+ <translation>Alınan Tutar</translation>
+ </message>
+ <message numerus="yes">
+ <source>matures in %n more block(s)</source>
+ <translation><numerusform>%n ek blok sonrasında olgunlaşacak</numerusform><numerusform>%n ek blok sonrasında olgunlaşacak</numerusform></translation>
+ </message>
+ <message>
+ <source>not accepted</source>
+ <translation>kabul edilmedi</translation>
+ </message>
+ <message>
+ <source>Debit</source>
+ <translation>Çekilen Tutar</translation>
+ </message>
+ <message>
+ <source>Total debit</source>
+ <translation>Toplam çekilen tutar</translation>
+ </message>
+ <message>
+ <source>Total credit</source>
+ <translation>Toplam alınan tutar</translation>
+ </message>
+ <message>
+ <source>Transaction fee</source>
+ <translation>İşlem ücreti</translation>
+ </message>
+ <message>
+ <source>Net amount</source>
+ <translation>Net tutar</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>İleti</translation>
+ </message>
+ <message>
+ <source>Comment</source>
+ <translation>Yorum</translation>
+ </message>
+ <message>
+ <source>Transaction ID</source>
+ <translation>İşlem ID'si</translation>
+ </message>
+ <message>
+ <source>Transaction total size</source>
+ <translation>İşlemin toplam boyutu</translation>
+ </message>
+ <message>
+ <source>Output index</source>
+ <translation>Çıktı indeksi</translation>
+ </message>
+ <message>
+ <source>Merchant</source>
+ <translation>Tüccar</translation>
+ </message>
+ <message>
+ <source>Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source>
+ <translation>Oluşturulan bitcoin'lerin harcanabilmelerinden önce %1 blok beklemeleri gerekmektedir. Bu blok, oluşturduğunuzda, blok zincirine eklenmesi için ağda yayınlandı. Zincire eklenmesi başarısız olursa, durumu "kabul edilmedi" olarak değiştirilecek ve harcanamayacaktır. Bu, bazen başka bir düğüm sizden birkaç saniye önce ya da sonra blok oluşturursa meydana gelebilir.</translation>
+ </message>
+ <message>
+ <source>Debug information</source>
+ <translation>Hata ayıklama bilgisi</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation>İşlem</translation>
+ </message>
+ <message>
+ <source>Inputs</source>
+ <translation>Girdiler</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Tutar</translation>
+ </message>
+ <message>
+ <source>true</source>
+ <translation>doğru</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation>yanlış</translation>
+ </message>
+</context>
<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
- <translation>Bu pano muamelenin ayrıntılı açıklamasını gösterir</translation>
+ <translation>Bu pano işlemin ayrıntılı açıklamasını gösterir</translation>
</message>
- </context>
+ <message>
+ <source>Details for %1</source>
+ <translation>%1 için ayrıntılar</translation>
+ </message>
+</context>
<context>
<name>TransactionTableModel</name>
<message>
+ <source>Date</source>
+ <translation>Tarih</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Tür</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>Etiket</translation>
</message>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>%n taneden daha fazla blok için açık</numerusform><numerusform>%n taneden daha fazla blok için açık</numerusform></translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>%1 değerine dek açık</translation>
+ </message>
+ <message>
+ <source>Offline</source>
+ <translation>Çevrim dışı</translation>
+ </message>
+ <message>
+ <source>Unconfirmed</source>
+ <translation>Doğrulanmamış</translation>
+ </message>
+ <message>
+ <source>Abandoned</source>
+ <translation>Terk edilmiş</translation>
+ </message>
+ <message>
+ <source>Confirming (%1 of %2 recommended confirmations)</source>
+ <translation>Doğrulanıyor (%1 kere doğrulandı, önerilen doğrulama sayısı %2)</translation>
+ </message>
+ <message>
+ <source>Confirmed (%1 confirmations)</source>
+ <translation>Doğrulandı (%1 doğrulama)</translation>
+ </message>
+ <message>
+ <source>Conflicted</source>
+ <translation>Uyuşmadı</translation>
+ </message>
+ <message>
+ <source>Immature (%1 confirmations, will be available after %2)</source>
+ <translation>Olgunlaşmamış (%1 doğrulama, %2 doğrulama sonra kullanılabilir olacaktır)</translation>
+ </message>
+ <message>
+ <source>This block was not received by any other nodes and will probably not be accepted!</source>
+ <translation>Bu blok başka hiçbir düğüm tarafından alınmamıştır ve muhtemelen kabul edilmeyecektir!</translation>
+ </message>
+ <message>
+ <source>Generated but not accepted</source>
+ <translation>Oluşturuldu ama kabul edilmedi</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Şununla alındı</translation>
+ </message>
+ <message>
+ <source>Received from</source>
+ <translation>Alındığı kişi</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Gönderildiği adres</translation>
+ </message>
+ <message>
+ <source>Payment to yourself</source>
+ <translation>Kendinize ödeme</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Madenden çıkarılan</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>sadece-izlenen</translation>
+ </message>
+ <message>
+ <source>(n/a)</source>
+ <translation>(mevcut değil)</translation>
+ </message>
<message>
<source>(no label)</source>
<translation>(etiket yok)</translation>
</message>
- </context>
+ <message>
+ <source>Transaction status. Hover over this field to show number of confirmations.</source>
+ <translation>İşlem durumu. Doğrulama sayısını görüntülemek için fare imlecini bu alanın üzerinde tutunuz.</translation>
+ </message>
+ <message>
+ <source>Date and time that the transaction was received.</source>
+ <translation>İşlemin alındığı tarih ve zaman.</translation>
+ </message>
+ <message>
+ <source>Type of transaction.</source>
+ <translation>İşlemin türü.</translation>
+ </message>
+ <message>
+ <source>Whether or not a watch-only address is involved in this transaction.</source>
+ <translation>Bu işleme sadece-izlenen bir adresin dahil edilip, edilmediği.</translation>
+ </message>
+ <message>
+ <source>User-defined intent/purpose of the transaction.</source>
+ <translation>İşlemin kullanıcı tanımlı amacı.</translation>
+ </message>
+ <message>
+ <source>Amount removed from or added to balance.</source>
+ <translation>Bakiyeden kaldırılan ya da bakiyeye eklenen tutar.</translation>
+ </message>
+</context>
<context>
<name>TransactionView</name>
<message>
+ <source>All</source>
+ <translation>Hepsi</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>Bugün</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>Bu hafta</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>Bu ay</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>Geçen ay</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>Bu yıl</translation>
+ </message>
+ <message>
+ <source>Range...</source>
+ <translation>Tarih Aralığı</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Şununla alındı</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Gönderildiği adres</translation>
+ </message>
+ <message>
+ <source>To yourself</source>
+ <translation>Kendinize</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Madenden çıkarılan</translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation>Diğer</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation>Aranacak adres ya da etiket giriniz</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation>En düşük tutar</translation>
+ </message>
+ <message>
+ <source>Abandon transaction</source>
+ <translation>İşlemden vazgeç</translation>
+ </message>
+ <message>
<source>Copy address</source>
<translation>Adres kopyala</translation>
</message>
@@ -1872,7 +2844,51 @@
</message>
<message>
<source>Copy amount</source>
- <translation>Miktarı kopyala</translation>
+ <translation>Tutarı kopyala</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>İşlem ID'sini kopyala</translation>
+ </message>
+ <message>
+ <source>Copy raw transaction</source>
+ <translation>Ham işlemi kopyala</translation>
+ </message>
+ <message>
+ <source>Copy full transaction details</source>
+ <translation>Tüm işlem ayrıntılarını kopyala</translation>
+ </message>
+ <message>
+ <source>Edit label</source>
+ <translation>Etiketi düzenle</translation>
+ </message>
+ <message>
+ <source>Show transaction details</source>
+ <translation>İşlem ayrıntılarını göster</translation>
+ </message>
+ <message>
+ <source>Export Transaction History</source>
+ <translation>İşlem Tarihçesini Dışarı Aktar</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Virgülle ayrılmış değerler dosyası (*.csv)</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation>Doğrulandı</translation>
+ </message>
+ <message>
+ <source>Watch-only</source>
+ <translation>Sadece izlenen</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Tarih</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Tür</translation>
</message>
<message>
<source>Label</source>
@@ -1883,26 +2899,90 @@
<translation>Adres</translation>
</message>
<message>
+ <source>ID</source>
+ <translation>ID</translation>
+ </message>
+ <message>
<source>Exporting Failed</source>
<translation>Dışarı aktarmada hata</translation>
</message>
- </context>
+ <message>
+ <source>There was an error trying to save the transaction history to %1.</source>
+ <translation>İşlem tarihçesinin %1 konumuna kaydedilmeye çalışıldığı sırada bir hata meydana geldi.</translation>
+ </message>
+ <message>
+ <source>Exporting Successful</source>
+ <translation>Dışarı Aktarma Başarılı</translation>
+ </message>
+ <message>
+ <source>The transaction history was successfully saved to %1.</source>
+ <translation>İşlem tarihçesi %1 konumuna başarıyla kaydedildi.</translation>
+ </message>
+ <message>
+ <source>Range:</source>
+ <translation>Tarih Aralığı:</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>Alıcı</translation>
+ </message>
+</context>
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
<source>Unit to show amounts in. Click to select another unit.</source>
- <translation>Meblağları göstermek için birim. Başka bir birim seçmek için tıklayınız.</translation>
+ <translation>Tutarı göstermek için birim. Başka bir birim seçmek için tıklayınız.</translation>
</message>
</context>
<context>
<name>WalletFrame</name>
- </context>
+ <message>
+ <source>No wallet has been loaded.</source>
+ <translation>Hiçbir cüzdan yüklenmedi.</translation>
+ </message>
+</context>
<context>
<name>WalletModel</name>
- </context>
+ <message>
+ <source>Send Coins</source>
+ <translation>Bitcoini Gönder</translation>
+ </message>
+</context>
<context>
<name>WalletView</name>
- </context>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;Dışarı aktar</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Mevcut sekmedeki verileri bir dosyaya aktar</translation>
+ </message>
+ <message>
+ <source>Backup Wallet</source>
+ <translation>Cüzdanı Yedekle</translation>
+ </message>
+ <message>
+ <source>Wallet Data (*.dat)</source>
+ <translation>Cüzdan Verileri (*.dat)</translation>
+ </message>
+ <message>
+ <source>Backup Failed</source>
+ <translation>Yedekleme Başarısız Oldu</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the wallet data to %1.</source>
+ <translation>Cüzdan verilerinin %1 konumuna kaydedilmesi sırasında bir hata meydana geldi.</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation>Yedekleme Başarılı</translation>
+ </message>
+ <message>
+ <source>The wallet data was successfully saved to %1.</source>
+ <translation>Cüzdan verileri %1 konumuna başarıyla kaydedildi.</translation>
+ </message>
+</context>
<context>
<name>bitcoin-core</name>
<message>
@@ -1926,22 +3006,30 @@
<translation>Komut satırı ve JSON-RPC komutlarını kabul et</translation>
</message>
<message>
+ <source>Accept connections from outside (default: 1 if no -proxy or -connect/-noconnect)</source>
+ <translation>Dışarıdan gelen bağlantıları kabul et (varsayılan: 1 eğer -proxy veya -connect/-noconnect yoksa)</translation>
+ </message>
+ <message>
+ <source>Connect only to the specified node(s); -noconnect or -connect=0 alone to disable automatic connections</source>
+ <translation>-noconnect ile yalnızca belirtilen düğümleri bağlayın veya yalnız otomatik bağlantıları devre dışı bırakmak için -connect=0 kullanın.</translation>
+ </message>
+ <message>
+ <source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
+ <translation>MIT yazılım lisansı altında dağıtılmıştır, beraberindeki %s ya da %s dosyasına bakınız.</translation>
+ </message>
+ <message>
<source>If &lt;category&gt; is not supplied or if &lt;category&gt; = 1, output all debugging information.</source>
- <translation>Eğer &lt;kategori&gt; belirtilmemişse ya da &lt;kategori&gt; = 1 ise, tüm hata ayıklama verilerini dök.</translation>
+ <translation>Eğer &lt;kategori&gt; belirtilmemişse ya da &lt;kategori&gt; = 1 ise, tüm hata ayıklama verilerini çıktı al.</translation>
</message>
<message>
<source>Prune configured below the minimum of %d MiB. Please use a higher number.</source>
- <translation>Budama, asgari değer olan %d MiB'den düşük olarak ayarlanmıştır. Lütfen daha yüksek bir sayı kullanınız.</translation>
+ <translation>Budama, en düşük değer olan %d MiB'den düşük olarak ayarlanmıştır. Lütfen daha yüksek bir sayı kullanınız.</translation>
</message>
<message>
<source>Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)</source>
<translation>Budama: son cüzdan eşleşmesi budanmış verilerin ötesine gitmektedir. -reindex kullanmanız gerekmektedir (Budanmış düğüm ise tüm blok zincirini tekrar indirmeniz gerekir.)</translation>
</message>
<message>
- <source>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, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Depolama gerekliliğini eski blokları budayarak (silerek) düşür. Bu kip -txindex ve -rescan 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 = MiB olarak blok dosyaları için kullanılacak hedef boyut)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Tekrar taramalar budanmış kipte mümkün değildir. Tüm blok zincirini tekrar indirecek olan -reindex seçeneğini kullanmanız gerekecektir.</translation>
</message>
@@ -1951,7 +3039,7 @@
</message>
<message>
<source>Fee (in %s/kB) to add to transactions you send (default: %s)</source>
- <translation>Yolladığınız muamelelere eklenecek ücret (%s/kB olarak) (varsayılan: %s)</translation>
+ <translation>Yolladığınız işlemlere eklenecek ücret (%s/kB olarak) (varsayılan: %s)</translation>
</message>
<message>
<source>Pruning blockstore...</source>
@@ -1979,7 +3067,7 @@
</message>
<message>
<source>Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)</source>
- <translation>Muameleler aktarılmadığında dahi beyaz listedeki eşlerden aktarılan muameleleri kabul et (varsayılan: %d)</translation>
+ <translation>İşlemler aktarılmadığında dahi beyaz listedeki eşlerden aktarılan işlemleri kabul et (varsayılan: %d)</translation>
</message>
<message>
<source>Bind to given address and always listen on it. Use [host]:port notation for IPv6</source>
@@ -1991,7 +3079,7 @@
</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>
+ <translation>Tüm cüzdan işlemlerini sil ve başlangıçta -rescan ile sadece blok zincirinin parçası olanları geri getir</translation>
</message>
<message>
<source>Error loading %s: You can't enable HD on a already existing non-HD wallet</source>
@@ -1999,19 +3087,27 @@
</message>
<message>
<source>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source>
- <translation>%s dosyasının okunması sırasında bir hata meydana geldi! Tüm anahtarlar doğru bir şekilde okundu, ancak muamele verileri ya da adres defteri unsurları hatalı veya eksik olabilir.</translation>
+ <translation>%s dosyasının okunması sırasında bir hata meydana geldi! Tüm anahtarlar doğru bir şekilde okundu, ancak işlem verileri ya da adres defteri ögeleri hatalı veya eksik olabilir.</translation>
</message>
<message>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
- <translation>Bir cüzdan muamelesi değiştiğinde komutu çalıştır (komuttaki %s muamele kimliği ile değiştirilecektir)</translation>
+ <translation>Bir cüzdan işlemi değiştiğinde komutu çalıştır (komuttaki %s işlem kimliği ile değiştirilecektir)</translation>
+ </message>
+ <message>
+ <source>Extra transactions to keep in memory for compact block reconstructions (default: %u)</source>
+ <translation>Daha küçük boyutlu blok yeniden yapılandırması için fazladan işlemleri bellekte tut. (varsayılan: %u)</translation>
+ </message>
+ <message>
+ <source>If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)</source>
+ <translation>Eğer bu blok zincirde yer alıyorsa onun ve atalarının geçerli olduğunu varsay ve potansiyel olarak onların betik doğrulamasını atla. (Tümünü doğrulamak için 0, varsayılan %s, testnet: %s)</translation>
</message>
<message>
<source>Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)</source>
- <translation>Müsaade edilen azami medyan eş zamanı değişiklik sınırının ayarlaması. Zamanın yerel perspektifi bu miktar kadar ileri ya da geri eşler tarafından etkilenebilir. (Varsayılan %u saniye)</translation>
+ <translation>İzin verilen edilen en yüksek medyan eş zamanı değişiklik sınırının ayarlaması. Zamanın yerel perspektifi bu miktar kadar ileri ya da geri eşler tarafından etkilenebilir. (Varsayılan %u saniye)</translation>
</message>
<message>
<source>Maximum total fees (in %s) to use in a single wallet transaction or raw transaction; setting this too low may abort large transactions (default: %s)</source>
- <translation>Tek cüzdan muamelesinde ya da ham muamelede kullanılacak azami toplam ücret (%s olarak); bunu çok düşük olarak ayarlamak büyük muameleleri iptal edebilir (varsayılan: %s)</translation>
+ <translation>Tek bir cüzdan işleminde ya da ham işlemde kullanılacak en yüksek toplam ücret (%s olarak); bunu çok düşük olarak ayarlamak büyük işlemleri iptal edebilir (varsayılan: %s)</translation>
</message>
<message>
<source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source>
@@ -2022,6 +3118,14 @@
<translation>%s programını faydalı buluyorsanız lütfen katkıda bulununuz. Yazılım hakkında daha fazla bilgi için %s adresini ziyaret ediniz.</translation>
</message>
<message>
+ <source>Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, &gt;%u = automatically prune block files to stay under the specified target size in MiB)</source>
+ <translation>Eski blokları budamayı (silme) etkinleştirerek depolama gereksinimlerini azaltın. Bu belirli blokları silmek için pruneblockchain uzak yordam çağrısına (RPC) izin verir. Eğer bloklar hedef mebibyte boyutuna ulaşırsa eski blokların otomatik olarak budanmasını sağlar. Bu kip, -txindex ve -rescan ile uyumsuzdur. Uyarı: Bu ayarı geri almak, blok zincirinin tamamını yeniden yüklemeyi gerektirir. (varsayılan: 0 = blok budaması devre dışı, 1 = RPC üzerinden manuel budamaya izin verir, &gt;%u = mebibyte olarak belirtilen hedef boyutun altında kalması için blok dosyalarını otomatik olarak budar)</translation>
+ </message>
+ <message>
+ <source>Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)</source>
+ <translation>Blok oluşturmaya dahil olan işlemler için en düşük ücret oranını (%s/kB olarak) ayarla. (varsayılan: %s)</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>
@@ -2030,6 +3134,10 @@
<translation>Blok veritabanı gelecekten gibi görünen bir blok içermektedir. Bu, bilgisayarınızın saat ve tarihinin yanlış ayarlanmış olmasından kaynaklanabilir. Blok veritabanını sadece bilgisayarınızın tarih ve saatinin doğru olduğundan eminseniz yeniden derleyin.</translation>
</message>
<message>
+ <source>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source>
+ <translation>Bu kararlı sürümden önceki bir deneme sürümüdür. - risklerini bilerek kullanma sorumluluğu sizdedir - bitcoin oluşturmak ya da ticari uygulamalar için kullanmayınız</translation>
+ </message>
+ <message>
<source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source>
<translation>Veritabanını çatallama öncesi duruma geri sarmak mümkün değil. Blok zincirini tekrar indirmeniz gerekmektedir</translation>
</message>
@@ -2038,6 +3146,22 @@
<translation>Dinlenecek portu haritalamak için UPnP kullan (varsayılan: dinlenildiğinde ve -proxy olmadığında 1)</translation>
</message>
<message>
+ <source>Username and hashed password for JSON-RPC connections. The field &lt;userpw&gt; comes in the format: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=&lt;USERNAME&gt;/rpcpassword=&lt;PASSWORD&gt; pair of arguments. This option can be specified multiple times</source>
+ <translation>JSON-RPC bağlantıları için kullanıcı adı ve karmalanmış parola. &lt;userpw&gt; alanı şu biçimdedir: &lt;KULLANICI ADI&gt;:&lt;SALT&gt;$&lt;HASH&gt;. Kanonik bir Python betiği share/rpcuser klasöründe bulunabilir. Ardından istemci normal şekilde rpcuser=&lt;KULLANICI ADI&gt;/rpcpassword=&lt;PAROLA&gt; argüman çiftini kullanarak bağlanabilir. Bu seçenek birden çok kez belirtilebilir.</translation>
+ </message>
+ <message>
+ <source>Wallet will not create transactions that violate mempool chain limits (default: %u)</source>
+ <translation>Cüzdan, zincir bellek alanı limitlerini ihlal eden işlem oluşturmayacak. (varsayılan: %u)</translation>
+ </message>
+ <message>
+ <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
+ <translation>Uyarı: Ağ üyeleri aralarında tamamen anlaşmış gibi gözükmüyor! Bazı madenciler sorun yaşıyor gibi görünmektedir.</translation>
+ </message>
+ <message>
+ <source>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source>
+ <translation>Uyarı: Ağ eşlerimizle tamamen anlaşamamışız gibi görünüyor! Güncelleme yapmanız gerekebilir ya da diğer düğümlerin güncelleme yapmaları gerekebilir.</translation>
+ </message>
+ <message>
<source>You need to rebuild the database using -reindex-chainstate to change -txindex</source>
<translation>-txindex'i değiştirmek için veritabanını -reindex-chainstate kullanarak tekrar inşa etmeniz gerekmektedir</translation>
</message>
@@ -2047,7 +3171,7 @@
</message>
<message>
<source>-maxmempool must be at least %d MB</source>
- <translation>-maxmempool asgari %d MB olmalıdır</translation>
+ <translation>-maxmempool en az %d MB olmalıdır</translation>
</message>
<message>
<source>&lt;category&gt; can be:</source>
@@ -2070,8 +3194,12 @@
<translation>Çözümlenemedi - %s adres: '%s'</translation>
</message>
<message>
+ <source>Chain selection options:</source>
+ <translation>Blok zinciri seçim ayarları:</translation>
+ </message>
+ <message>
<source>Change index out of range</source>
- <translation>Aralık dışında değişiklik endeksi</translation>
+ <translation>Aralık dışında değişiklik indeksi</translation>
</message>
<message>
<source>Connection options:</source>
@@ -2103,7 +3231,7 @@
</message>
<message>
<source>Enable publish hash transaction in &lt;address&gt;</source>
- <translation>Karma değer muamelesinin &lt;adres&gt;te yayınlanmasını etkinleştir</translation>
+ <translation>Karma değer işleminin &lt;adres&gt;te yayınlanmasını etkinleştir</translation>
</message>
<message>
<source>Enable publish raw block in &lt;address&gt;</source>
@@ -2111,11 +3239,11 @@
</message>
<message>
<source>Enable publish raw transaction in &lt;address&gt;</source>
- <translation>Ham muamelenin &lt;adres&gt;te yayınlanmasını etkinleştir</translation>
+ <translation>Ham işlemin &lt;adres&gt;te yayınlanmasını etkinleştir</translation>
</message>
<message>
<source>Enable transaction replacement in the memory pool (default: %u)</source>
- <translation>Bellek alanında muamele değiştirmeyi etkinleştir (varsayılan: %u)</translation>
+ <translation>Bellek alanında işlem değiştirmeyi etkinleştir (varsayılan: %u)</translation>
</message>
<message>
<source>Error initializing block database</source>
@@ -2163,7 +3291,7 @@
</message>
<message>
<source>Incorrect or no genesis block found. Wrong datadir for network?</source>
- <translation>Yanlış ya da bulunamamış doğuş bloku. Şebeke için yanlış veri klasörü mü?</translation>
+ <translation>Yanlış ya da bulunamamış doğuş bloğu. Ağ için yanlış veri klasörü mü?</translation>
</message>
<message>
<source>Initialization sanity check failed. %s is shutting down.</source>
@@ -2175,15 +3303,15 @@
</message>
<message>
<source>Invalid amount for -%s=&lt;amount&gt;: '%s'</source>
- <translation>-%s=&lt;meblağ&gt; için geçersiz meblağ: '%s'</translation>
+ <translation>-%s=&lt;tutar&gt; için geçersiz tutar: '%s'</translation>
</message>
<message>
<source>Invalid amount for -fallbackfee=&lt;amount&gt;: '%s'</source>
- <translation> -fallbackfee=&lt;meblağ&gt; için geçersiz meblağ: '%s'</translation>
+ <translation> -fallbackfee=&lt;tutar&gt; için geçersiz tutar: '%s'</translation>
</message>
<message>
<source>Keep the transaction memory pool below &lt;n&gt; megabytes (default: %u)</source>
- <translation>Muamele bellek alanını &lt;n&gt; megabayttan düşük tut (varsayılan: %u)</translation>
+ <translation>İşlem bellek alanını &lt;n&gt; megabayttan düşük tut (varsayılan: %u)</translation>
</message>
<message>
<source>Loading banlist...</source>
@@ -2199,7 +3327,7 @@
</message>
<message>
<source>Only connect to nodes in network &lt;net&gt; (ipv4, ipv6 or onion)</source>
- <translation>Sadece &lt;net&gt; şebekesindeki düğümlere bağlan (ipv4, ipv6 veya onion)</translation>
+ <translation>Sadece &lt;net&gt; ağındaki düğümlere bağlan (ipv4, ipv6 veya onion)</translation>
</message>
<message>
<source>Print this help message and exit</source>
@@ -2219,11 +3347,11 @@
</message>
<message>
<source>Rebuild chain state and block index from the blk*.dat files on disk</source>
- <translation>Zincir durumu ve blok endeksini diskteki blk*.dat dosyalarından yeniden derle</translation>
+ <translation>Zincir durumu ve blok indeksini diskteki blk*.dat dosyalarından yeniden derle</translation>
</message>
<message>
<source>Rebuild chain state from the currently indexed blocks</source>
- <translation>Zincir durumunu güncel olarak endekslenen bloklardan yeniden derle</translation>
+ <translation>Zincir durumunu güncel olarak indekslenen bloklardan yeniden derle</translation>
</message>
<message>
<source>Rewinding blocks...</source>
@@ -2235,7 +3363,7 @@
</message>
<message>
<source>Set maximum block size in bytes (default: %d)</source>
- <translation>Azami blok boyutunu bayt olarak ayarla (varsayılan: %d)</translation>
+ <translation>En yüksek blok boyutunu bayt olarak ayarla (varsayılan: %d)</translation>
</message>
<message>
<source>Specify wallet file (within data directory)</source>
@@ -2266,6 +3394,10 @@
<translation>Dinleme portunu haritalamak için UPnP kullan (varsayılan: %u)</translation>
</message>
<message>
+ <source>Use the test chain</source>
+ <translation>Test blok zincirini kullan</translation>
+ </message>
+ <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation>Kullanıcı Aracı açıklaması (%s) güvensiz karakterler içermektedir.</translation>
</message>
@@ -2295,7 +3427,7 @@
</message>
<message>
<source>Allow JSON-RPC connections from specified source. Valid for &lt;ip&gt; 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</source>
- <translation>Belirtilen kaynaktan JSON-RPC bağlantılarını kabul et. Bir &lt;ip&gt; için geçerli olanlar şunlardır: salt IP adresi (mesela 1.2.3.4), bir şebeke/ağ maskesi (örneğin 1.2.3.4/255.255.255.0) ya da bir şebeke/CIDR (mesela 1.2.3.4/24). Bu seçenek birden fazla kez belirtilebilir</translation>
+ <translation>Belirtilen kaynaktan JSON-RPC bağlantılarını kabul et. Bir &lt;ip&gt; için geçerli olanlar şunlardır: IP adresi (mesela 1.2.3.4), bir ağ/ağ maskesi (örneğin 1.2.3.4/255.255.255.0) ya da bir ağ/CIDR (mesela 1.2.3.4/24). Bu seçenek birden fazla kez belirtilebilir</translation>
</message>
<message>
<source>Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6</source>
@@ -2323,19 +3455,19 @@
</message>
<message>
<source>Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)</source>
- <translation>Bundan düşük ücretler (%s/kB olarak) aktarma, oluşturma ve muamele yaratma için sıfır değerinde ücret olarak kabul edilir (varsayılan: %s)</translation>
+ <translation>Bundan düşük ücretler (%s/kB olarak) aktarma, oluşturma ve işlem yaratma için sıfır değerinde ücret olarak kabul edilir (varsayılan: %s)</translation>
</message>
<message>
<source>If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)</source>
- <translation>Eğer paytxfee ayarlanmadıysa kafi derecede ücret ekleyin ki muameleler teyite vasati n blok içinde başlasın (varsayılan: %u)</translation>
+ <translation>Eğer paytxfee ayarlanmadıysa kafi derecede ücret ekleyin ki işlemler teyite vasati n blok içinde başlasın (varsayılan: %u)</translation>
</message>
<message>
<source>Invalid amount for -maxtxfee=&lt;amount&gt;: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)</source>
- <translation>-maxtxfee=&lt;tutar&gt; için geçersiz tutar: '%s' (Sıkışmış muameleleri önlemek için en az %s değerinde asgari aktarım ücretine eşit olmalıdır)</translation>
+ <translation>-maxtxfee=&lt;tutar&gt; için geçersiz tutar: '%s' (Sıkışmış işlemleri önlemek için en az %s değerinde en düşük aktarım ücretine eşit olmalıdır)</translation>
</message>
<message>
<source>Maximum size of data in data carrier transactions we relay and mine (default: %u)</source>
- <translation>Aktardığımız ve oluşturduğumuz veri taşıyıcı muamelelerindeki azami veri boyutu (varsayılan: %u)</translation>
+ <translation>Aktardığımız ve oluşturduğumuz veri taşıyıcı işlemlerindeki en yüksek veri boyutu (varsayılan: %u)</translation>
</message>
<message>
<source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
@@ -2343,11 +3475,11 @@
</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>
+ <translation>Yüksek öncelikli/düşük ücretli işlemlerin en yüksek boyutunu bayt olarak ayarla (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>
+ <translation>Bu işlem, tutar düşüldükten sonra göndermek için çok düşük</translation>
</message>
<message>
<source>Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start</source>
@@ -2355,7 +3487,7 @@
</message>
<message>
<source>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</source>
- <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>
+ <translation>Beyaz listeye alınan eşler DoS yasaklamasına uğramazlar ve işlemleri 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>
@@ -2399,7 +3531,7 @@
</message>
<message>
<source>Keep at most &lt;n&gt; unconnectable transactions in memory (default: %u)</source>
- <translation>Hafızada en çok &lt;n&gt; bağlanılamaz muamele tut (varsayılan: %u)</translation>
+ <translation>Hafızada en çok &lt;n&gt; bağlanılamaz işlem tut (varsayılan: %u)</translation>
</message>
<message>
<source>Need to specify a port with -whitebind: '%s'</source>
@@ -2407,7 +3539,7 @@
</message>
<message>
<source>Node relay options:</source>
- <translation>Düğüm röle seçenekleri:</translation>
+ <translation>Düğüm aktarma seçenekleri:</translation>
</message>
<message>
<source>RPC server options:</source>
@@ -2419,15 +3551,15 @@
</message>
<message>
<source>Rescan the block chain for missing wallet transactions on startup</source>
- <translation>Başlangıçta blok zincirini eksik cüzdan muameleleri için tekrar tara</translation>
+ <translation>Başlangıçta blok zincirini eksik cüzdan işlemleri için tekrar tara</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>
+ <translation>İzleme/hata ayıklama verilerini debug.log dosyası yerine konsola gönder</translation>
</message>
<message>
<source>Send transactions as zero-fee transactions if possible (default: %u)</source>
- <translation>Muameleleri mümkünse ücretsiz olarak gönder (varsayılan: %u)</translation>
+ <translation>İşlemleri mümkünse ücretsiz olarak gönder (varsayılan: %u)</translation>
</message>
<message>
<source>Show all debugging options (usage: --help -help-debug)</source>
@@ -2439,11 +3571,11 @@
</message>
<message>
<source>Signing transaction failed</source>
- <translation>Muamelenin imzalanması başarısız oldu</translation>
+ <translation>İşlemin imzalanması başarısız oldu</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>
+ <translation>İşlemdeki bitcoin tutarı ücreti ödemek için çok düşük</translation>
</message>
<message>
<source>This is experimental software.</source>
@@ -2455,23 +3587,23 @@
</message>
<message>
<source>Tor control port to use if onion listening enabled (default: %s)</source>
- <translation>Eğer onion dinlenmesi etkinse kullanılacak Tor kontrol portu (varsayılan: %s)</translation>
+ <translation>Eğer onion dinlemesi etkinse kullanılacak Tor kontrol portu (varsayılan: %s)</translation>
</message>
<message>
<source>Transaction amount too small</source>
- <translation>Muamele meblağı çok düşük</translation>
+ <translation>İşlem tutarı çok düşük</translation>
</message>
<message>
<source>Transaction too large for fee policy</source>
- <translation>Ücret politikası için çok büyük muamele</translation>
+ <translation>Ücret politikası için işlem çok büyük</translation>
</message>
<message>
<source>Transaction too large</source>
- <translation>Muamele çok büyük</translation>
+ <translation>İşlem çok büyük</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>
+ <translation>Bu bilgisayarda %s ögesine bağlanılamadı (bağlanma %s hatasını verdi)</translation>
</message>
<message>
<source>Upgrade wallet to latest format on startup</source>
@@ -2487,15 +3619,15 @@
</message>
<message>
<source>Warning: unknown new rules activated (versionbit %i)</source>
- <translation>İkaz: bilinmeyen yeni kurallar etkinleştirilmiştir (versionbit %i)</translation>
+ <translation>Uyarı: bilinmeyen yeni kurallar etkinleştirilmiştir (versionbit %i)</translation>
</message>
<message>
<source>Whether to operate in a blocks only mode (default: %u)</source>
- <translation>Salt blok kipinde çalışılıp çalışılmayacağı (varsayılan: %u)</translation>
+ <translation>Sadece blok kipinde çalışılıp çalışılmayacağı (varsayılan: %u)</translation>
</message>
<message>
<source>Zapping all transactions from wallet...</source>
- <translation>Cüzdandaki tüm muameleler kaldırılıyor...</translation>
+ <translation>Cüzdandaki tüm işlemler kaldırılıyor...</translation>
</message>
<message>
<source>ZeroMQ notification options:</source>
@@ -2523,19 +3655,23 @@
</message>
<message>
<source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
- <translation>-maxtxfee çok yüksek bir değere ayarlanmış! Bu denli yüksek ücretler tek bir muamelede ödenebilir.</translation>
+ <translation>-maxtxfee çok yüksek bir değere ayarlanmış! Bu denli yüksek ücretler tek bir işlemde ödenebilir.</translation>
</message>
<message>
<source>Do not keep transactions in the mempool longer than &lt;n&gt; hours (default: %u)</source>
- <translation>Muameleleri bellek alanında &lt;n&gt; saatten fazla tutma (varsayılan: %u)</translation>
+ <translation>İşlemleri bellek alanında &lt;n&gt; saatten fazla tutma (varsayılan: %u)</translation>
</message>
<message>
<source>Equivalent bytes per sigop in transactions for relay and mining (default: %u)</source>
- <translation>Oluşturma ve aktarşa muamelelerinde sigop başına eşdeğer bayt (varsayılan: %u)</translation>
+ <translation>Oluşturma ve aktarma işlemlerinde sigop başına eşdeğer bayt (varsayılan: %u)</translation>
</message>
<message>
<source>Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)</source>
- <translation>Bundan düşük ücretler (%s/kB olarak) muamele oluşturulması için sıfır değerinde ücret olarak kabul edilir (varsayılan: %s)</translation>
+ <translation>Bundan düşük ücretler (%s/kB olarak) işlem oluşturulması için sıfır değerinde ücret olarak kabul edilir (varsayılan: %s)</translation>
+ </message>
+ <message>
+ <source>Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)</source>
+ <translation>Yerel aktarma politikasını ihlal etseler bile beyaz listedeki eşlerden gelen işlemlerin aktarılmasını zorla (varsayılan: %d)</translation>
</message>
<message>
<source>How thorough the block verification of -checkblocks is (0-4, default: %u)</source>
@@ -2543,7 +3679,7 @@
</message>
<message>
<source>Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)</source>
- <translation>Muamelelerin tamamının indeksini tut, getrawtransaction rpc çağrısı tarafından kullanılır (varsayılan: %u)</translation>
+ <translation>İşlemlerin tamamının indeksini tut, getrawtransaction rpc çağrısı tarafından kullanılır (varsayılan: %u)</translation>
</message>
<message>
<source>Number of seconds to keep misbehaving peers from reconnecting (default: %u)</source>
@@ -2551,15 +3687,31 @@
</message>
<message>
<source>Output debugging information (default: %u, supplying &lt;category&gt; is optional)</source>
- <translation>Hata ayıklama bilgisi dök (varsayılan: %u, &lt;kategori&gt; sağlanması seçime dayalıdır)</translation>
+ <translation>Hata ayıklama bilgisini dök (varsayılan: %u, &lt;kategori&gt; sağlanması seçime dayalıdır)</translation>
+ </message>
+ <message>
+ <source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect/-noconnect)</source>
+ <translation>Adres sayısı azaldıysa DNS sorgulamasıyla eş adresleri ara (varsayılan: 1 -connect/-noconnect kullanılmadıysa)</translation>
+ </message>
+ <message>
+ <source>Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(1) (default: %d)</source>
+ <translation>Ham işlemin serileştirilmesini ayarlar veya blok non-verbose, non-segwit(0) veya segwit(1) kipinde onaltılık değeri döndürür (default: %d)</translation>
</message>
<message>
<source>Support filtering of blocks and transaction with bloom filters (default: %u)</source>
- <translation>Blokların ve muamelelerin bloom filtreleri ile süzülmesini destekle (varsayılan: %u)</translation>
+ <translation>Blokların ve işlemlerin bloom filtreleri ile süzülmesini destekle (varsayılan: %u)</translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you may pay when fee estimates are not available.</source>
+ <translation>İşlem ücret tahminleri mevcut olmadığında ödeyebileceğiniz işlem ücreti budur.</translation>
+ </message>
+ <message>
+ <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit %s and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
+ <translation>Bu ürün OpenSSL Projesi tarafından geliştirilen OpenSSL araç takımınında kullanılmak üzere yazılan yazılımları %s Eric Young tarafından yazılmış şifreleme yazılımını ve Thomas Bernard tarafından yazılmış UPnP yazılımını içerir.</translation>
</message>
<message>
<source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source>
- <translation>Şebeke sürümü zincirinin toplam boyutu (%i) azami boyutu geçmektedir (%i). Kullanıcı aracı açıklamasının sayısı veya boyutunu azaltınız.</translation>
+ <translation>Ağ sürümü zincirinin toplam boyutu (%i) en yüksek boyutu geçmektedir (%i). Kullanıcı aracı açıklamasının sayısı veya boyutunu azaltınız.</translation>
</message>
<message>
<source>Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)</source>
@@ -2579,11 +3731,19 @@
</message>
<message>
<source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source>
- <translation>İkaz: bilinmeyen blok sürümü oluşturulmaya çalışılıyor. Bilinmeyen kuralların işlemesi mümkündür.</translation>
+ <translation>Uyarı: Bilinmeyen blok sürümü oluşturulmaya çalışılıyor. Bilinmeyen kuralların işlemesi mümkündür.</translation>
</message>
<message>
<source>Warning: Wallet file corrupt, data salvaged! Original %s saved as %s in %s; if your balance or transactions are incorrect you should restore from a backup.</source>
- <translation>Uyarı: wallet.dat bozuk, veriler geri kazanıldı! Özgün %s, %s olarak %s klasörüne kaydedildi; bakiyeniz ya da muameleleriniz yanlışsa bir yedeklemeden tekrar yüklemeniz gerekir.</translation>
+ <translation>Uyarı: wallet.dat bozuk, veriler geri kazanıldı! Özgün %s, %s olarak %s klasörüne kaydedildi; bakiyeniz ya da işlemleriniz yanlışsa bir yedeklemeden tekrar yüklemeniz gerekir.</translation>
+ </message>
+ <message>
+ <source>Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR notated network (e.g. 1.2.3.0/24). Can be specified multiple times.</source>
+ <translation>Beyaz listeye eklenen eşler verilen IP adresinden (ör. 1.2.3.4) veya CIDR ağından (ör. 1.2.3.0/24) bağlanabilir. Değerler birden çok kez kullanılabilir.</translation>
+ </message>
+ <message>
+ <source>%s is set very high!</source>
+ <translation>%s çok yüksek ayarlanmış!</translation>
</message>
<message>
<source>(default: %s)</source>
@@ -2606,6 +3766,10 @@
<translation>Geçersiz -proxy adresi: '%s'</translation>
</message>
<message>
+ <source>Keypool ran out, please call keypoolrefill first</source>
+ <translation>Keypool tükendi, lütfen önce keypoolrefill'i çağırın</translation>
+ </message>
+ <message>
<source>Listen for JSON-RPC connections on &lt;port&gt; (default: %u or testnet: %u)</source>
<translation>JSON-RPC bağlantılarını &lt;port&gt; üzerinde dinle (varsayılan: %u veya tesnet: %u)</translation>
</message>
@@ -2619,15 +3783,15 @@
</message>
<message>
<source>Make the wallet broadcast transactions</source>
- <translation>Cüzdanın muameleleri yayınlamasını sağla</translation>
+ <translation>Cüzdanın işlemleri 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>
+ <translation>Her bağlantı için en yüksek alım tamponu, &lt;n&gt;*1000 bayt (varsayılan: %u)</translation>
</message>
<message>
<source>Maximum per-connection send buffer, &lt;n&gt;*1000 bytes (default: %u)</source>
- <translation>Her bağlantı için azami yollama tamponu, &lt;n&gt;*1000 bayt (varsayılan: %u)</translation>
+ <translation>Her bağlantı için çok gönderme tamponu, &lt;n&gt;*1000 bayt (varsayılan: %u)</translation>
</message>
<message>
<source>Prepend debug output with timestamp (default: %u)</source>
@@ -2635,19 +3799,23 @@
</message>
<message>
<source>Relay and mine data carrier transactions (default: %u)</source>
- <translation>Veri taşıyıcı muameleleri oluştur ve aktar (varsayılan: %u)</translation>
+ <translation>Veri taşıyıcı işlemleri oluştur ve aktar (varsayılan: %u)</translation>
</message>
<message>
<source>Relay non-P2SH multisig (default: %u)</source>
<translation>P2SH olmayan çoklu imzaları aktar (varsayılan: %u)</translation>
</message>
<message>
+ <source>Send transactions with full-RBF opt-in enabled (default: %u)</source>
+ <translation>İşlemleri full-RBF opt-in ile gönder etkinleştirildi (default: %u)</translation>
+ </message>
+ <message>
<source>Set key pool size to &lt;n&gt; (default: %u)</source>
<translation>Anahtar alan boyutunu &lt;n&gt; değerine ayarla (varsayılan: %u)</translation>
</message>
<message>
<source>Set maximum BIP141 block weight (default: %d)</source>
- <translation>Azami BIP141 blok ağırlığını ayarla (varsayılan: %d)</translation>
+ <translation>En yüksek BIP141 blok ağırlığını ayarla (varsayılan: %d)</translation>
</message>
<message>
<source>Set the number of threads to service RPC calls (default: %d)</source>
@@ -2659,7 +3827,7 @@
</message>
<message>
<source>Specify connection timeout in milliseconds (minimum: 1, default: %d)</source>
- <translation>Bağlantı zaman aşım süresini milisaniye olarak belirt (asgari: 1, varsayılan: %d)</translation>
+ <translation>Bağlantı zaman aşım süresini milisaniye olarak belirt (en düşüki: 1, varsayılan: %d)</translation>
</message>
<message>
<source>Specify pid file (default: %s)</source>
@@ -2667,15 +3835,43 @@
</message>
<message>
<source>Spend unconfirmed change when sending transactions (default: %u)</source>
- <translation>Gönderme muamelelerinde teyit edilmemiş para üstünü harca (varsayılan: %u)</translation>
+ <translation>Gönderme işlemlerinde doğrulanmamış para üstünü harca (varsayılan: %u)</translation>
+ </message>
+ <message>
+ <source>Starting network threads...</source>
+ <translation>Ağ iş parçacıkları başlatılıyor...</translation>
+ </message>
+ <message>
+ <source>The wallet will avoid paying less than the minimum relay fee.</source>
+ <translation>Cüzdan en az aktarma ücretinden daha az ödeme yapmaktan sakınacaktır.</translation>
+ </message>
+ <message>
+ <source>This is the minimum transaction fee you pay on every transaction.</source>
+ <translation>Bu her işlemde ödeceğiniz en düşük işlem ücretidir.</translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you will pay if you send a transaction.</source>
+ <translation>Eğer bir gönderme işlemi yaparsanız bu ödeyeceğiniz işlem ücretidir.</translation>
</message>
<message>
<source>Threshold for disconnecting misbehaving peers (default: %u)</source>
<translation>Aksaklık gösteren eşlerle bağlantıyı kesme sınırı (varsayılan: %u)</translation>
</message>
<message>
+ <source>Transaction amounts must not be negative</source>
+ <translation>İşlem tutarı negatif olmamalıdır</translation>
+ </message>
+ <message>
+ <source>Transaction has too long of a mempool chain</source>
+ <translation>İşlem çok uzun bir mempool zincirine sahip</translation>
+ </message>
+ <message>
+ <source>Transaction must have at least one recipient</source>
+ <translation>İşlemin en az bir alıcısı olması gerekir</translation>
+ </message>
+ <message>
<source>Unknown network specified in -onlynet: '%s'</source>
- <translation>-onlynet için bilinmeyen bir şebeke belirtildi: '%s'</translation>
+ <translation>-onlynet için bilinmeyen bir ağ belirtildi: '%s'</translation>
</message>
<message>
<source>Insufficient funds</source>
@@ -2687,7 +3883,7 @@
</message>
<message>
<source>Add a node to connect to and attempt to keep the connection open</source>
- <translation>Bağlanılacak düğüm ekle ve bağlantıyı zinde tutmaya çalış</translation>
+ <translation>Bağlanılacak düğüm ekle ve bağlantıyı sürekli açık tutmaya çalış</translation>
</message>
<message>
<source>Loading wallet...</source>
@@ -2703,7 +3899,7 @@
</message>
<message>
<source>Rescanning...</source>
- <translation>Yeniden tarama...</translation>
+ <translation>Yeniden taranıyor...</translation>
</message>
<message>
<source>Done loading</source>
diff --git a/src/qt/locale/bitcoin_uk.ts b/src/qt/locale/bitcoin_uk.ts
index 9c46c18224..4cff6bf370 100644
--- a/src/qt/locale/bitcoin_uk.ts
+++ b/src/qt/locale/bitcoin_uk.ts
@@ -41,10 +41,78 @@
<source>&amp;Delete</source>
<translation>&amp;Видалити</translation>
</message>
- </context>
+ <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>C&amp;hoose</source>
+ <translation>О&amp;брати</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>Це ваші адреси Bitcoin для надсилання платежів. Завжди перевіряйте суму та адресу одержувача перед відправленням монет.</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>Це ваші адреси Bitcoin для отримання платежів. Для кожної транзакції рекомендується використовувати нову адресу одержувача.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Скопіювати адресу</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Зкопіювати&amp;Створити мітку</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Редагувати</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Експотувати список адрес</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Файли (*.csv) розділеі комами</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Експортування пройшло не успішно</translation>
+ </message>
+ <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>
- </context>
+ <message>
+ <source>Label</source>
+ <translation>Мітка</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Адреса</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(немає мітки)</translation>
+ </message>
+</context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -63,7 +131,95 @@
<source>Repeat new passphrase</source>
<translation>Повторіть пароль</translation>
</message>
- </context>
+ <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>Encrypt wallet</source>
+ <translation>Зашифрувати гаманець</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Ця операція потребує пароль для розблокування гаманця.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Розблокувати гаманець</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Ця операція потребує пароль для розшифрування гаманця.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Дешифрувати гаманець</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Змінити пароль</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Введіть старий пароль та новий пароль до гаманця.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Підтвердіть шифрування гаманця</translation>
+ </message>
+ <message>
+ <source>Warning: If you encrypt your wallet and lose your passphrase, you will &lt;b&gt;LOSE ALL OF YOUR BITCOINS&lt;/b&gt;!</source>
+ <translation>УВАГА: Якщо ви зашифруєте гаманець і забудете пароль, ви &lt;b&gt;ВТРАТИТЕ ВСІ СВОЇ БІТКОІНИ&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Ви дійсно хочете зашифрувати свій гаманець?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Гаманець зашифровано</translation>
+ </message>
+ <message>
+ <source>%1 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>%1 буде закрито зараз, щоб завершити процес шифрування. Пам'ятайте, що шифрування гаманця не може повністю захистити ваші біткойни від крадіжки шкідливими програмами, у випадку якщо ваш комп'ютер буде інфіковано.</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>Wallet encryption failed</source>
+ <translation>Не вдалося зашифрувати гаманець</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Виникла помилка під час шифрування гаманця. Ваш гаманець не було зашифровано.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>Введені паролі не співпадають.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Не вдалося розблокувати гаманець</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>Введений пароль є невірним.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Не вдалося розшифрувати гаманець</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>Пароль було успішно змінено.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Увага: Ввімкнено Caps Lock!</translation>
+ </message>
+</context>
<context>
<name>BanTableModel</name>
<message>
@@ -118,6 +274,10 @@
<translation>П&amp;ро %1</translation>
</message>
<message>
+ <source>Show information about %1</source>
+ <translation>Показати інформацію про %1</translation>
+ </message>
+ <message>
<source>About &amp;Qt</source>
<translation>&amp;Про Qt</translation>
</message>
@@ -130,6 +290,10 @@
<translation>&amp;Параметри...</translation>
</message>
<message>
+ <source>Modify configuration options for %1</source>
+ <translation>Редагувати параметри для %1</translation>
+ </message>
+ <message>
<source>&amp;Encrypt Wallet...</source>
<translation>&amp;Шифрування гаманця...</translation>
</message>
@@ -154,6 +318,22 @@
<translation>Відкрити &amp;URI</translation>
</message>
<message>
+ <source>Click to disable network activity.</source>
+ <translation>Натисніть, щоб вимкнути активність мережі.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>Мережева активність вимкнена.</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>Натисніть, щоб знову активувати мережеву активність.</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>Синхронізація заголовків (%1%)...</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>Переіндексація блоків на диску ...</translation>
</message>
@@ -258,8 +438,12 @@
<translation><numerusform>%n активне з'єднання з мережею Bitcoin</numerusform><numerusform>%n активні з'єднання з мережею Bitcoin</numerusform><numerusform>%n активних з'єднань з мережею Bitcoin</numerusform></translation>
</message>
<message>
- <source>No block source available...</source>
- <translation>Недоступно жодного джерела блоків...</translation>
+ <source>Indexing blocks on disk...</source>
+ <translation>Індексація блоків на диску ...</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk...</source>
+ <translation>Обробка блоків на диску...</translation>
</message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
@@ -294,6 +478,18 @@
<translation>Синхронізовано</translation>
</message>
<message>
+ <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
+ <translation>Показати довідку %1 для отримання переліку можливих параметрів командного рядка.</translation>
+ </message>
+ <message>
+ <source>%1 client</source>
+ <translation>%1 клієнт</translation>
+ </message>
+ <message>
+ <source>Connecting to peers...</source>
+ <translation>Підключення до вузлів...</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>Синхронізується...</translation>
</message>
@@ -336,6 +532,14 @@
<translation>Отримані транзакції</translation>
</message>
<message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation>Генерація HD ключа &lt;b&gt;увімкнена&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation>Генерація HD ключа&lt;b&gt;вимкнена&lt;/b&gt;</translation>
+ </message>
+ <message>
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
<translation>&lt;b&gt;Зашифрований&lt;/b&gt; гаманець &lt;b&gt;розблоковано&lt;/b&gt;</translation>
</message>
@@ -343,7 +547,11 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>&lt;b&gt;Зашифрований&lt;/b&gt; гаманець &lt;b&gt;заблоковано&lt;/b&gt;</translation>
</message>
- </context>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>Сталася фатальна помилка. Помилки не сумісні з подальщою роботою. Гаманець буде закрито.</translation>
+ </message>
+</context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -414,7 +622,83 @@
<source>Confirmed</source>
<translation>Підтверджені</translation>
</message>
- </context>
+ <message>
+ <source>Copy address</source>
+ <translation>Скопіювати адресу</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Скопіювати мітку</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Скопіювати суму</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <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 dust</source>
+ <translation>Скопіювати інше</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Скопіювати решту</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation>(%1 заблоковано)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>так</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>ні</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation>Може відрізнятися на +/- %1 сатоші за введені</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>немає мітки</translation>
+ </message>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation>решта з %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(решта)</translation>
+ </message>
+</context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -437,7 +721,39 @@
<source>&amp;Address</source>
<translation>&amp;Адреса</translation>
</message>
- </context>
+ <message>
+ <source>New receiving address</source>
+ <translation>Нова адреса для отримання</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Нова адреса для відправлення</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Редагувати адресу для отримання</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Редагувати адресу для відправлення</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>Введена адреса "%1" не є адресою в мережі Bitcoin.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book.</source>
+ <translation>Введена адреса «%1» вже присутня в адресній книзі.</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Неможливо розблокувати гаманець.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Не вдалося згенерувати нові ключі.</translation>
+ </message>
+</context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -472,6 +788,10 @@
<translation>(%1-бітний)</translation>
</message>
<message>
+ <source>About %1</source>
+ <translation>Про %1</translation>
+ </message>
+ <message>
<source>Command-line options</source>
<translation>Параметри командного рядка</translation>
</message>
@@ -507,7 +827,11 @@
<source>Show splash screen on startup (default: %u)</source>
<translation>Показувати заставку під час запуску (типово: %u)</translation>
</message>
- </context>
+ <message>
+ <source>Reset all settings changed in the GUI</source>
+ <translation>Скинути налаштування, які було змінено через графічний інтерфейс користувача</translation>
+ </message>
+</context>
<context>
<name>Intro</name>
<message>
@@ -515,6 +839,14 @@
<translation>Вітання</translation>
</message>
<message>
+ <source>Welcome to %1.</source>
+ <translation>Ласкаво просимо до %1.</translation>
+ </message>
+ <message>
+ <source>As this is the first time the program is launched, you can choose where %1 will store its data.</source>
+ <translation>Оскільки це перший запуск програми, ви можете обрати де %1 буде зберігати дані.</translation>
+ </message>
+ <message>
<source>Use the default data directory</source>
<translation>Використовувати типовий каталог даних</translation>
</message>
@@ -546,14 +878,50 @@
<translation>Форма</translation>
</message>
<message>
+ <source>Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source>
+ <translation>Нещодавні транзакції ще не відображаються, тому баланс вашого гаманця може бути неточним. Ця інформація буде вірною після того, як ваш гаманець завершить синхронізацію з мережею біткойн, врахровуйте показники нижче.</translation>
+ </message>
+ <message>
+ <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source>
+ <translation>Спроба видправити біткойни, які ще не відображаються, не буде прийнята мережею.</translation>
+ </message>
+ <message>
+ <source>Number of blocks left</source>
+ <translation>Залишилося блоків</translation>
+ </message>
+ <message>
+ <source>Unknown...</source>
+ <translation>Невідомо...</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation>Час останнього блоку</translation>
</message>
<message>
+ <source>Progress</source>
+ <translation>Прогрес</translation>
+ </message>
+ <message>
+ <source>Progress increase per hour</source>
+ <translation>Прогрес за годину</translation>
+ </message>
+ <message>
+ <source>calculating...</source>
+ <translation>рахування...</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation>Орієнтовний час до кінця синхронізації</translation>
+ </message>
+ <message>
<source>Hide</source>
<translation>Приховати</translation>
</message>
- </context>
+ <message>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation>Невідомо. Синхронізація заголовків (%1%)...</translation>
+ </message>
+</context>
<context>
<name>OpenURIDialog</name>
<message>
@@ -572,7 +940,11 @@
<source>Select payment request file</source>
<translation>Виберіть файл запиту платежу</translation>
</message>
- </context>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>Виберіть файл запиту платежу</translation>
+ </message>
+</context>
<context>
<name>OptionsDialog</name>
<message>
@@ -584,6 +956,10 @@
<translation>&amp;Головні</translation>
</message>
<message>
+ <source>&amp;Start %1 on system login</source>
+ <translation>&amp;Запускати %1 при вході в систему</translation>
+ </message>
+ <message>
<source>Size of &amp;database cache</source>
<translation>Розмір &amp;кешу бази даних</translation>
</message>
@@ -720,6 +1096,10 @@
<translation>&amp;Вікно</translation>
</message>
<message>
+ <source>Hide tray icon</source>
+ <translation>Сховати іконку в треї</translation>
+ </message>
+ <message>
<source>Show only a tray icon after minimizing the window.</source>
<translation>Показувати лише іконку в треї після згортання вікна.</translation>
</message>
@@ -865,6 +1245,14 @@
</context>
<context>
<name>PaymentServer</name>
+ <message>
+ <source>Payment request error</source>
+ <translation>Помилка запиту платежу</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation>Обробка URI</translation>
+ </message>
</context>
<context>
<name>PeerTableModel</name>
@@ -876,7 +1264,11 @@
<source>Node/Service</source>
<translation>Вузол/Сервіс</translation>
</message>
- </context>
+ <message>
+ <source>Ping</source>
+ <translation>Затримка</translation>
+ </message>
+</context>
<context>
<name>QObject</name>
<message>
@@ -922,10 +1314,30 @@
</context>
<context>
<name>QObject::QObject</name>
- </context>
+ <message>
+ <source>Error: %1</source>
+ <translation>Помилка: %1</translation>
+ </message>
+</context>
<context>
<name>QRImageWidget</name>
- </context>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;Зберегти зображення...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>&amp;Копіювати зображення</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>Зберегти QR-код</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>Зображення PNG (*.png)</translation>
+ </message>
+</context>
<context>
<name>RPCConsole</name>
<message>
@@ -1037,6 +1449,14 @@
<translation>Клієнт користувача</translation>
</message>
<message>
+ <source>Decrease font size</source>
+ <translation>Зменшити розмір шрифту</translation>
+ </message>
+ <message>
+ <source>Increase font size</source>
+ <translation>Збільшити розмір шрифту</translation>
+ </message>
+ <message>
<source>Services</source>
<translation>Сервіси</translation>
</message>
@@ -1137,6 +1557,10 @@
<translation>Наберіть &lt;b&gt;help&lt;/b&gt; для перегляду доступних команд.</translation>
</message>
<message>
+ <source>Network activity disabled</source>
+ <translation>Мережева активність вимкнена.</translation>
+ </message>
+ <message>
<source>%1 B</source>
<translation>%1 Б</translation>
</message>
@@ -1255,7 +1679,23 @@
<source>Remove</source>
<translation>Вилучити</translation>
</message>
- </context>
+ <message>
+ <source>Copy URI</source>
+ <translation>Скопіювати адресу</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Скопіювати мітку</translation>
+ </message>
+ <message>
+ <source>Copy message</source>
+ <translation>Скопіювати повідомлення</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Скопіювати суму</translation>
+ </message>
+</context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -1274,10 +1714,58 @@
<source>&amp;Save Image...</source>
<translation>&amp;Зберегти зображення...</translation>
</message>
+ <message>
+ <source>Payment information</source>
+ <translation>Інформація про платіж</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Адреса</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Кількість</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Мітка</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Повідомлення</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
- </context>
+ <message>
+ <source>Date</source>
+ <translation>Дата</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Мітка</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Повідомлення</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>немає мітки</translation>
+ </message>
+ <message>
+ <source>(no message)</source>
+ <translation>(без повідомлення)</translation>
+ </message>
+ <message>
+ <source>(no amount requested)</source>
+ <translation>(без суми)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation>Запрошено</translation>
+ </message>
+</context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1405,6 +1893,10 @@
<translation>Пил:</translation>
</message>
<message>
+ <source>Confirmation time target:</source>
+ <translation>Час підтвердження:</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>Очистити &amp;все</translation>
</message>
@@ -1420,7 +1912,39 @@
<source>S&amp;end</source>
<translation>&amp;Відправити</translation>
</message>
- </context>
+ <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 dust</source>
+ <translation>Скопіювати інше</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Скопіювати решту</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>немає мітки</translation>
+ </message>
+</context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -1499,10 +2023,18 @@
<source>Memo:</source>
<translation>Нотатка:</translation>
</message>
- </context>
+ <message>
+ <source>Enter a label for this address to add it to your address book</source>
+ <translation>Введіть мітку для цієї адреси для додавання її в адресну книгу</translation>
+ </message>
+</context>
<context>
<name>SendConfirmationDialog</name>
- </context>
+ <message>
+ <source>Yes</source>
+ <translation>Так</translation>
+ </message>
+</context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1596,7 +2128,59 @@
<source>Reset all verify message fields</source>
<translation>Скинути всі поля перевірки повідомлення</translation>
</message>
- </context>
+ <message>
+ <source>Click "Sign Message" to generate signature</source>
+ <translation>Натисніть кнопку «Підписати повідомлення», для отримання підпису</translation>
+ </message>
+ <message>
+ <source>The entered address is invalid.</source>
+ <translation>Введена адреса не співпадає.</translation>
+ </message>
+ <message>
+ <source>Please check the address and try again.</source>
+ <translation>Будь ласка, перевірте адресу та спробуйте ще.</translation>
+ </message>
+ <message>
+ <source>The entered address does not refer to a key.</source>
+ <translation>Введена адреса не відноситься до ключа.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock was cancelled.</source>
+ <translation>Розблокування гаманця було скасоване.</translation>
+ </message>
+ <message>
+ <source>Private key for the entered address is not available.</source>
+ <translation>Приватний ключ для введеної адреси недоступний. </translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation>Не вдалося підписати повідомлення.</translation>
+ </message>
+ <message>
+ <source>Message signed.</source>
+ <translation>Повідомлення підписано.</translation>
+ </message>
+ <message>
+ <source>The signature could not be decoded.</source>
+ <translation>Підпис не можливо декодувати.</translation>
+ </message>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation>Будь ласка, перевірте підпис та спробуйте ще.</translation>
+ </message>
+ <message>
+ <source>The signature did not match the message digest.</source>
+ <translation>Підпис не збігається з хешем повідомлення.</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation>Не вдалося перевірити повідомлення.</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation>Повідомлення перевірено.</translation>
+ </message>
+</context>
<context>
<name>SplashScreen</name>
<message>
@@ -1613,19 +2197,359 @@
</context>
<context>
<name>TransactionDesc</name>
- </context>
+ <message>
+ <source>Open until %1</source>
+ <translation>Відкрито до %1</translation>
+ </message>
+ <message>
+ <source>Status</source>
+ <translation>Статут</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Дата</translation>
+ </message>
+ <message>
+ <source>Source</source>
+ <translation>Джерело</translation>
+ </message>
+ <message>
+ <source>Generated</source>
+ <translation>Згенеровано</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>Від</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>невідомо</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation>Отримувач</translation>
+ </message>
+ <message>
+ <source>own address</source>
+ <translation>Власна адреса</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>мітка</translation>
+ </message>
+ <message>
+ <source>Credit</source>
+ <translation>Кредит</translation>
+ </message>
+ <message>
+ <source>not accepted</source>
+ <translation>не прийнято</translation>
+ </message>
+ <message>
+ <source>Debit</source>
+ <translation>Дебет</translation>
+ </message>
+ <message>
+ <source>Total debit</source>
+ <translation>Загальний дебет</translation>
+ </message>
+ <message>
+ <source>Total credit</source>
+ <translation>Загальний кредит</translation>
+ </message>
+ <message>
+ <source>Transaction fee</source>
+ <translation>Комісія за транзакцію</translation>
+ </message>
+ <message>
+ <source>Net amount</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>
+ <message>
+ <source>Transaction total size</source>
+ <translation>Розмір транзакції</translation>
+ </message>
+ <message>
+ <source>Merchant</source>
+ <translation>Продавець</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation>Транзакція</translation>
+ </message>
+ <message>
+ <source>Inputs</source>
+ <translation>Входи</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Кількість</translation>
+ </message>
+ <message>
+ <source>true</source>
+ <translation>вірний</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation>хибний</translation>
+ </message>
+</context>
<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Даний діалог показує детальну статистику по вибраній транзакції</translation>
</message>
- </context>
+ <message>
+ <source>Details for %1</source>
+ <translation>Інформація по %1</translation>
+ </message>
+</context>
<context>
<name>TransactionTableModel</name>
- </context>
+ <message>
+ <source>Date</source>
+ <translation>Дата</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Тип</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Мітка</translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>Відкрито до %1</translation>
+ </message>
+ <message>
+ <source>Offline</source>
+ <translation>Поза мережею</translation>
+ </message>
+ <message>
+ <source>Unconfirmed</source>
+ <translation>Не підтверджено</translation>
+ </message>
+ <message>
+ <source>Abandoned</source>
+ <translation>Відкинуті</translation>
+ </message>
+ <message>
+ <source>Confirming (%1 of %2 recommended confirmations)</source>
+ <translation>Підтверджується (%1 з %2 рекомендованих підтверджень)</translation>
+ </message>
+ <message>
+ <source>Confirmed (%1 confirmations)</source>
+ <translation>Підтверджено (%1 підтверджень)</translation>
+ </message>
+ <message>
+ <source>Conflicted</source>
+ <translation>Суперечить</translation>
+ </message>
+ <message>
+ <source>Immature (%1 confirmations, will be available after %2)</source>
+ <translation>Повністтю не підтверджено (%1 підтверджень, будуть доступні після %2)</translation>
+ </message>
+ <message>
+ <source>This block was not received by any other nodes and will probably not be accepted!</source>
+ <translation>Цей блок не був отриманий жодними іншими вузлами і, ймовірно, не буде прийнятий!</translation>
+ </message>
+ <message>
+ <source>Generated but not accepted</source>
+ <translation>Згенеровано (не підтверджено)</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Отримано з</translation>
+ </message>
+ <message>
+ <source>Received from</source>
+ <translation>Отримано від</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Відправлені на</translation>
+ </message>
+ <message>
+ <source>Payment to yourself</source>
+ <translation>Відправлено собі</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Добуті</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>немає мітки</translation>
+ </message>
+ <message>
+ <source>Transaction status. Hover over this field to show number of confirmations.</source>
+ <translation>Статус транзакції. Наведіть вказівник на це поле, щоб показати кількість підтверджень.</translation>
+ </message>
+ <message>
+ <source>Date and time that the transaction was received.</source>
+ <translation>Дата і час, коли транзакцію було отримано.</translation>
+ </message>
+ <message>
+ <source>Type of transaction.</source>
+ <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>
+</context>
<context>
<name>TransactionView</name>
+ <message>
+ <source>All</source>
+ <translation>Всі</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>Сьогодні</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>На цьому тижні</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>Цього місяця</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>Минулого місяця</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>Цього року</translation>
+ </message>
+ <message>
+ <source>Range...</source>
+ <translation>Діапазон від:</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Отримано з</translation>
+ </message>
+ <message>
+ <source>Sent to</source>
+ <translation>Відправлені на</translation>
+ </message>
+ <message>
+ <source>To yourself</source>
+ <translation>Відправлені собі</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Добуті</translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation>Інше</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation>Введіть адресу чи мітку для пошуку</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation>Мінімальна сума</translation>
+ </message>
+ <message>
+ <source>Abandon transaction</source>
+ <translation>Відмовитися від транзакції</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Скопіювати адресу</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Скопіювати мітку</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Скопіювати суму</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Скопіювати ID транзакції </translation>
+ </message>
+ <message>
+ <source>Copy raw transaction</source>
+ <translation>Скопіювати RAW транзакцію</translation>
+ </message>
+ <message>
+ <source>Copy full transaction details</source>
+ <translation>Скопіювати повні деталі транзакції</translation>
+ </message>
+ <message>
+ <source>Edit label</source>
+ <translation>Редагувати мітку</translation>
+ </message>
+ <message>
+ <source>Show transaction details</source>
+ <translation>Показати деталі транзакції</translation>
+ </message>
+ <message>
+ <source>Export Transaction History</source>
+ <translation>Експортувати історію транзакцій</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Файли (*.csv) розділеі комами</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation>Підтверджено</translation>
+ </message>
+ <message>
+ <source>Watch-only</source>
+ <translation>Тільки спостереження:</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Дата</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Тип</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Мітка</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Адреса</translation>
+ </message>
+ <message>
+ <source>ID</source>
+ <translation>Ідентифікатор</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Експортування пройшло не успішно</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
@@ -1642,7 +2566,35 @@
</context>
<context>
<name>WalletView</name>
- </context>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;Експорт</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Експортувати дані з поточної вкладки в файл</translation>
+ </message>
+ <message>
+ <source>Backup Wallet</source>
+ <translation>Зробити резервне копіювання гаманця</translation>
+ </message>
+ <message>
+ <source>Wallet Data (*.dat)</source>
+ <translation>Данi гаманця (*.dat)</translation>
+ </message>
+ <message>
+ <source>Backup Failed</source>
+ <translation>Помилка резервного копіювання</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation>Резервну копію створено успішно</translation>
+ </message>
+ <message>
+ <source>The wallet data was successfully saved to %1.</source>
+ <translation>Дані гаманця успішно збережено в %1.</translation>
+ </message>
+</context>
<context>
<name>bitcoin-core</name>
<message>
@@ -1678,10 +2630,6 @@
<translation>Операція відсікання: остання синхронізація вмісту гаманцю не обмежується діями над скороченими данними. Вам необхідно зробити переіндексацію -reindex (заново завантажити веcь ланцюжок блоків в разі появи скороченого ланцюга)</translation>
</message>
<message>
- <source>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, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Зменшити вимоги до наявного простору на носії даних за допомогою скорочення ланцюжка (видалення старих блоків). Цей режим несумісний з параметрами -txindex та -rescan. Увага: при поверненні до типового значення видалені частини ланцюжка буде повторно завантажено. (типово: 0 = вимкнути скорочення ланцюжка, &gt;%u = очікуваний розмір файлів блоків в МіБ)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Неможливо провести повторне сканування зі скороченим ланцюжком. Вам необхідно використати -reindex для завантаження повного ланцюжка блоків.</translation>
</message>
@@ -1750,6 +2698,10 @@
<translation>Параметри з'єднання:</translation>
</message>
<message>
+ <source>Copyright (C) %i-%i</source>
+ <translation>Всі права збережено. %i-%i</translation>
+ </message>
+ <message>
<source>Corrupted block database detected</source>
<translation>Виявлено пошкоджений блок бази даних</translation>
</message>
@@ -1830,6 +2782,10 @@
<translation>Підключатися тільки до вузлів в мережі &lt;net&gt; (ipv4, ipv6 або onion)</translation>
</message>
<message>
+ <source>Print this help message and exit</source>
+ <translation>Надрукувати це довідкове повідомлення та вийти</translation>
+ </message>
+ <message>
<source>Print version and exit</source>
<translation>Версія для друку і виходу</translation>
</message>
@@ -1842,6 +2798,10 @@
<translation>Використання скороченого ланцюжка блоків несумісне з параметром -txindex.</translation>
</message>
<message>
+ <source>Rewinding blocks...</source>
+ <translation>Відтворення блоків...</translation>
+ </message>
+ <message>
<source>Set database cache size in megabytes (%d to %d, default: %d)</source>
<translation>Встановити розмір кешу бази даних в мегабайтах (від %d до %d, типово: %d)</translation>
</message>
@@ -2214,10 +3174,18 @@
<translation>Ретранслювати не-P2SH транзакції з мультипідписом (типово: %u)</translation>
</message>
<message>
+ <source>Send transactions with full-RBF opt-in enabled (default: %u)</source>
+ <translation>Надіслати транзакції з увімкненням full-RBF opt-in (типово: %u)</translation>
+ </message>
+ <message>
<source>Set key pool size to &lt;n&gt; (default: %u)</source>
<translation>Встановити розмір пулу ключів &lt;n&gt; (типово: %u)</translation>
</message>
<message>
+ <source>Set maximum BIP141 block weight (default: %d)</source>
+ <translation>Встановити максимальний розмір блоку BIP141 (за замовчуванням: %d)</translation>
+ </message>
+ <message>
<source>Set the number of threads to service RPC calls (default: %d)</source>
<translation>Встановити число потоків для обслуговування викликів RPC (типово: %d)</translation>
</message>
@@ -2238,10 +3206,38 @@
<translation>Витрачати непідтверджену решту при відправленні транзакцій (типово: %u)</translation>
</message>
<message>
+ <source>Starting network threads...</source>
+ <translation>Запуск мережевих потоків...</translation>
+ </message>
+ <message>
+ <source>The wallet will avoid paying less than the minimum relay fee.</source>
+ <translation>Гаманець не не переведе кошти якщо комісія менше мінімальної плати за транзакцію.</translation>
+ </message>
+ <message>
+ <source>This is the minimum transaction fee you pay on every transaction.</source>
+ <translation>Це мінімальна плата за транзакцію, яку ви сплачуєте за кожну операцію.</translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you will pay if you send a transaction.</source>
+ <translation>Це транзакційна комісія, яку ви сплатите, якщо будете надсилати транзакцію.</translation>
+ </message>
+ <message>
<source>Threshold for disconnecting misbehaving peers (default: %u)</source>
<translation>Поріг відключення учасників з поганою поведінкою (типово: %u)</translation>
</message>
<message>
+ <source>Transaction amounts must not be negative</source>
+ <translation>Сума транзакції занадто мала (зменьшіть комісію, якщо можливо)</translation>
+ </message>
+ <message>
+ <source>Transaction has too long of a mempool chain</source>
+ <translation>У транзакції занадто довгий ланцюг</translation>
+ </message>
+ <message>
+ <source>Transaction must have at least one recipient</source>
+ <translation>У транзакції повинен бути щонайменше один одержувач</translation>
+ </message>
+ <message>
<source>Unknown network specified in -onlynet: '%s'</source>
<translation>Невідома мережа вказана в -onlynet: «%s»</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ur_PK.ts b/src/qt/locale/bitcoin_ur_PK.ts
index 923198c91a..bd0ef617ae 100644
--- a/src/qt/locale/bitcoin_ur_PK.ts
+++ b/src/qt/locale/bitcoin_ur_PK.ts
@@ -41,9 +41,25 @@
<source>&amp;Delete</source>
<translation>مٹا</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>C&amp;hoose</source>
+ <translation>چننا</translation>
+ </message>
</context>
<context>
<name>AddressTableModel</name>
+ <message>
+ <source>Address</source>
+ <translation> پتہ</translation>
+ </message>
</context>
<context>
<name>AskPassphraseDialog</name>
@@ -152,6 +168,10 @@
<source>Copy &amp;Address</source>
<translation>کاپی پتہ</translation>
</message>
+ <message>
+ <source>Address</source>
+ <translation> پتہ</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
@@ -200,6 +220,10 @@
</context>
<context>
<name>TransactionView</name>
+ <message>
+ <source>Address</source>
+ <translation> پتہ</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
diff --git a/src/qt/locale/bitcoin_uz@Cyrl.ts b/src/qt/locale/bitcoin_uz@Cyrl.ts
index fe10a8a8e7..3898c441af 100644
--- a/src/qt/locale/bitcoin_uz@Cyrl.ts
+++ b/src/qt/locale/bitcoin_uz@Cyrl.ts
@@ -246,10 +246,6 @@
<translation><numerusform>%n та Bitcoin тармоғига фаол уланиш мавжуд</numerusform></translation>
</message>
<message>
- <source>No block source available...</source>
- <translation>Блок манбалари мавжуд эмас...</translation>
- </message>
- <message>
<source>%1 behind</source>
<translation>%1 орқада</translation>
</message>
diff --git a/src/qt/locale/bitcoin_vi_VN.ts b/src/qt/locale/bitcoin_vi_VN.ts
index c27111a52a..8c4bececa1 100644
--- a/src/qt/locale/bitcoin_vi_VN.ts
+++ b/src/qt/locale/bitcoin_vi_VN.ts
@@ -41,6 +41,26 @@
<source>&amp;Delete</source>
<translation>&amp;Xó&amp;a</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Chọn địa chỉ để gửi coin đến</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Chọn địa chỉ để nhận coin</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>Chọn</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Địa chỉ gửi đến</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Địa chỉ nhận</translation>
+ </message>
</context>
<context>
<name>AddressTableModel</name>
diff --git a/src/qt/locale/bitcoin_zh_CN.ts b/src/qt/locale/bitcoin_zh_CN.ts
index 8267a4f0e3..77d32402d3 100644
--- a/src/qt/locale/bitcoin_zh_CN.ts
+++ b/src/qt/locale/bitcoin_zh_CN.ts
@@ -330,6 +330,10 @@
<translation>点击重新开启网络活动。</translation>
</message>
<message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>同步区块头 (%1%)...</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>正在为数据块重建索引...</translation>
</message>
@@ -441,10 +445,6 @@
<source>Processing blocks on disk...</source>
<translation>正在处理数据块...</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></translation>
@@ -486,6 +486,10 @@
<translation>%1 客戶</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>正在连接到节点……</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>更新中...</translation>
</message>
@@ -1931,7 +1935,11 @@
<source>(no amount requested)</source>
<translation>(无请求金额)</translation>
</message>
- </context>
+ <message>
+ <source>Requested</source>
+ <translation>总额</translation>
+ </message>
+</context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -2183,6 +2191,10 @@
<translation>警告:未知的更改地址</translation>
</message>
<message>
+ <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source>
+ <translation>你选择的找零地址未被包含在本钱包中,你钱包中的部分或全部金额将被发送至该地址。你确定要这样做吗?</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(无标签)</translation>
</message>
@@ -2464,6 +2476,14 @@
<translation>0/未确认,%1</translation>
</message>
<message>
+ <source>in memory pool</source>
+ <translation>在内存池中</translation>
+ </message>
+ <message>
+ <source>not in memory pool</source>
+ <translation>不在内存池中</translation>
+ </message>
+ <message>
<source>abandoned</source>
<translation>已抛弃</translation>
</message>
@@ -2971,10 +2991,6 @@
<translation>修剪:最后的钱包同步超过了修剪的数据。你需要通过 -reindex (重新下载整个区块链以防修剪节点)</translation>
</message>
<message>
- <source>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, &gt;%u = target size in MiB to use for block files)</source>
- <translation>通过修剪(删除)旧数据块减少存储需求。此模式与 -txindex 和 -rescan不兼容。警告:还原此设置需要重新下载整个区块链。(默认: 0 = 禁用修剪数据块, &gt;%u = 数据块文件目标大小,单位 MiB)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>无法在开启修剪的状态下重扫描,请使用 -reindex重新下载完整的区块链。</translation>
</message>
@@ -3209,6 +3225,10 @@
<translation>使用UPnp映射监听端口 (默认: %u) </translation>
</message>
<message>
+ <source>Use the test chain</source>
+ <translation>使用测试链</translation>
+ </message>
+ <message>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation>用户代理评论(%s)包含不安全的字符。</translation>
</message>
@@ -3225,6 +3245,10 @@
<translation>钱包 %s 在外部的数据目录 %s</translation>
</message>
<message>
+ <source>Wallet debugging/testing options:</source>
+ <translation>钱包调试/测试选项:</translation>
+ </message>
+ <message>
<source>Wallet options:</source>
<translation>钱包选项:</translation>
</message>
diff --git a/src/qt/locale/bitcoin_zh_HK.ts b/src/qt/locale/bitcoin_zh_HK.ts
index 2f3a8d1f16..44d4ac1e76 100644
--- a/src/qt/locale/bitcoin_zh_HK.ts
+++ b/src/qt/locale/bitcoin_zh_HK.ts
@@ -41,10 +41,70 @@
<source>&amp;Delete</source>
<translation>刪除 &amp;D</translation>
</message>
- </context>
+ <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>C&amp;hoose</source>
+ <translation>選擇 &amp;h</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>付款地址</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>收款地址</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>複製地址 &amp;C</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>複製標記 &amp;L</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>編輯 &amp;E</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>匯出地址清單</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>逗號分隔檔 (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>匯出失敗</translation>
+ </message>
+ <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>
- </context>
+ <message>
+ <source>Label</source>
+ <translation>標記</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>地址</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(無標記)</translation>
+ </message>
+</context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -63,7 +123,91 @@
<source>Repeat new passphrase</source>
<translation>重複新密碼</translation>
</message>
- </context>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>加密錢包</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>這個動作需要你的錢包密碼來將錢包解鎖。</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>解鎖錢包</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>這個動作需要你的錢包密碼來將錢包解密。</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>解密錢包</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>更改密碼</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>輸入舊密碼和新密碼至錢包。</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>確認錢包加密</translation>
+ </message>
+ <message>
+ <source>Warning: If you encrypt your wallet and lose your passphrase, you will &lt;b&gt;LOSE ALL OF YOUR BITCOINS&lt;/b&gt;!</source>
+ <translation>警告: 如果你將錢包加密後又忘記密碼,你就會&lt;b&gt;失去所有 Bitcoin 了&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>你確定要把錢包加密嗎?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>錢包已加密</translation>
+ </message>
+ <message>
+ <source>%1 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>%1 現在要關閉來完成加密程序。請記得將錢包加密不能完全防止你的 Bitcoins 經被入侵電腦的惡意程式偷取。</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>Wallet encryption failed</source>
+ <translation>錢包加密失敗</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>因內部錯誤導致錢包加密失敗,你的錢包尚未加密。</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>提供的密碼不一致。</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>錢包解鎖失敗</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>用來解密錢包的密碼不對。</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>錢包解密失敗</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>錢包密碼已成功更改。</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>警告: Caps Lock 已啟用!</translation>
+ </message>
+</context>
<context>
<name>BanTableModel</name>
<message>
@@ -114,6 +258,14 @@
<translation>結束應用程式</translation>
</message>
<message>
+ <source>&amp;About %1</source>
+ <translation>關於 %1 &amp;A</translation>
+ </message>
+ <message>
+ <source>Show information about %1</source>
+ <translation>顯示 %1 的相關資訊</translation>
+ </message>
+ <message>
<source>About &amp;Qt</source>
<translation>關於 Qt &amp;Q</translation>
</message>
@@ -126,6 +278,10 @@
<translation>選項... &amp;O</translation>
</message>
<message>
+ <source>Modify configuration options for %1</source>
+ <translation>修正 %1 的設定選項</translation>
+ </message>
+ <message>
<source>&amp;Encrypt Wallet...</source>
<translation>加密錢包... &amp;E</translation>
</message>
@@ -201,9 +357,51 @@
<source>Show or hide the main Window</source>
<translation>顯示或隱藏主視窗</translation>
</message>
+ <message>
+ <source>&amp;File</source>
+ <translation>檔案 &amp;F</translation>
+ </message>
+ <message>
+ <source>&amp;Settings</source>
+ <translation>設定 &amp;S</translation>
+ </message>
+ <message>
+ <source>&amp;Help</source>
+ <translation>說明 &amp;H</translation>
+ </message>
+ <message>
+ <source>Request payments (generates QR codes and bitcoin: URIs)</source>
+ <translation>要求付款 (產生QR碼 bitcoin: URIs)</translation>
+ </message>
+ <message>
+ <source>Indexing blocks on disk...</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>Date: %1
+</source>
+ <translation>日期: %1
+</translation>
+ </message>
</context>
<context>
<name>CoinControlDialog</name>
+ <message>
+ <source>(no label)</source>
+ <translation>(無標記)</translation>
+ </message>
</context>
<context>
<name>EditAddressDialog</name>
@@ -216,6 +414,10 @@
</context>
<context>
<name>Intro</name>
+ <message>
+ <source>Error</source>
+ <translation>錯誤</translation>
+ </message>
</context>
<context>
<name>ModalOverlay</name>
@@ -237,28 +439,144 @@
</context>
<context>
<name>QObject</name>
+ <message>
+ <source>Enter a Bitcoin address (e.g. %1)</source>
+ <translation>輸入一個 Bitcoin 位址 (例如 %1)</translation>
+ </message>
+ <message>
+ <source>%1 d</source>
+ <translation>%1 日</translation>
+ </message>
+ <message>
+ <source>%1 h</source>
+ <translation>%1 小時</translation>
+ </message>
+ <message>
+ <source>%1 m</source>
+ <translation>%1 分</translation>
+ </message>
+ <message>
+ <source>%1 s</source>
+ <translation>%1 秒</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>沒有</translation>
+ </message>
+ <message>
+ <source>N/A</source>
+ <translation>N/A</translation>
+ </message>
+ <message>
+ <source>%1 ms</source>
+ <translation>%1 亳秒</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation><numerusform>%n 秒</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation><numerusform>%n 分鐘</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation><numerusform>%n 小時</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation><numerusform>%n 日</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation><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></translation>
+ </message>
</context>
<context>
<name>QObject::QObject</name>
</context>
<context>
<name>QRImageWidget</name>
- </context>
+ <message>
+ <source>Save QR Code</source>
+ <translation>儲存 QR 碼</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>PNG 影像(*.png)</translation>
+ </message>
+</context>
<context>
<name>RPCConsole</name>
+ <message>
+ <source>N/A</source>
+ <translation>N/A</translation>
+ </message>
+ <message>
+ <source>&amp;Information</source>
+ <translation>資訊 &amp;I</translation>
+ </message>
+ <message>
+ <source>Debug window</source>
+ <translation>除錯視窗</translation>
+ </message>
+ <message>
+ <source>General</source>
+ <translation>一般</translation>
+ </message>
+ <message>
+ <source>Received</source>
+ <translation>已接收</translation>
+ </message>
+ <message>
+ <source>Sent</source>
+ <translation>已送出</translation>
+ </message>
+ <message>
+ <source>Version</source>
+ <translation>版本</translation>
+ </message>
</context>
<context>
<name>ReceiveCoinsDialog</name>
</context>
<context>
<name>ReceiveRequestDialog</name>
+ <message>
+ <source>Address</source>
+ <translation>地址</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>標記</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>標記</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(無標記)</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
- </context>
+ <message>
+ <source>(no label)</source>
+ <translation>(無標記)</translation>
+ </message>
+</context>
<context>
<name>SendCoinsEntry</name>
</context>
@@ -279,15 +597,47 @@
</context>
<context>
<name>TransactionDesc</name>
+ <message>
+ <source>Open until %1</source>
+ <translation>開放至 %1</translation>
+ </message>
</context>
<context>
<name>TransactionDescDialog</name>
</context>
<context>
<name>TransactionTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>標記</translation>
+ </message>
+ <message>
+ <source>Open until %1</source>
+ <translation>開放至 %1</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(無標記)</translation>
+ </message>
</context>
<context>
<name>TransactionView</name>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>逗號分隔檔 (*.csv)</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>標記</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>地址</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>匯出失敗</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
@@ -300,8 +650,28 @@
</context>
<context>
<name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation>匯出 &amp;E</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>把目前分頁的資料匯出至檔案</translation>
+ </message>
</context>
<context>
<name>bitcoin-core</name>
- </context>
+ <message>
+ <source>Information</source>
+ <translation>資訊</translation>
+ </message>
+ <message>
+ <source>Warning</source>
+ <translation>警告</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>錯誤</translation>
+ </message>
+</context>
</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_zh_TW.ts b/src/qt/locale/bitcoin_zh_TW.ts
index bdcf966297..bd0533a83e 100644
--- a/src/qt/locale/bitcoin_zh_TW.ts
+++ b/src/qt/locale/bitcoin_zh_TW.ts
@@ -330,6 +330,10 @@
<translation>按一下就又會使用網路。</translation>
</message>
<message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>正在同步前導資料(%1%)中...</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>正在為磁碟裡的區塊重建索引...</translation>
</message>
@@ -441,10 +445,6 @@
<source>Processing blocks on disk...</source>
<translation>正在處理磁碟裡的區塊資料...</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></translation>
@@ -486,6 +486,10 @@
<translation>%1 客戶端軟體</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>正在跟其他節點連線中...</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>正在趕進度...</translation>
</message>
@@ -2201,6 +2205,14 @@
<translation>警告: 不明的找零位址</translation>
</message>
<message>
+ <source>Confirm custom change address</source>
+ <translation>自定找零位址確認</translation>
+ </message>
+ <message>
+ <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source>
+ <translation>選擇的找零位址並不屬於這個錢包。部份或是全部的錢會被送到這個位址去。你確定嗎?</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(無標記)</translation>
</message>
@@ -3019,10 +3031,6 @@
<translation>修剪模式:錢包的最後同步狀態是在被修剪掉的區塊資料中。你需要用 -reindex 參數執行(會重新下載整個區塊鏈)</translation>
</message>
<message>
- <source>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, &gt;%u = target size in MiB to use for block files)</source>
- <translation>修剪(刪除)掉老舊區塊來減少需要的儲存空間。這種模式會關閉錢包功能,並且和 -txindex 及 -rescan 參數不相容。警告: 從這種模式還原會需要重新下載一整個區塊鏈。(預設值: 0 表示不修剪區塊,&gt;%u 表示為區塊檔案的目標大小,單位是百萬位元組 MiB)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>在修剪模式下沒辦法重新掃描區塊鏈。你需要配合使用 -reindex 參數來重新下載整個區塊鏈。</translation>
</message>
@@ -3087,6 +3095,14 @@
<translation>當錢包有交易改變時要執行的指令(指令中的 %s 會被取代成交易識別碼)</translation>
</message>
<message>
+ <source>Extra transactions to keep in memory for compact block reconstructions (default: %u)</source>
+ <translation>為了將摘要區塊完整回組而額外保留在記憶體中的交易數量(預設值: %u)</translation>
+ </message>
+ <message>
+ <source>If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)</source>
+ <translation>假設已經在區塊鏈中的區塊以及其先前的區塊都合法,因此對它們略過指令碼驗證(0 表示一律要驗證,預設值: %s, 測試網路: %s)</translation>
+ </message>
+ <message>
<source>Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)</source>
<translation>跟其他節點的時間差最高可接受的中位數值。本機所認為的時間可能會被其他節點影響,往前或往後在這個值之內。(預設值: %u 秒)</translation>
</message>
@@ -3103,6 +3119,14 @@
<translation>如果你覺得 %s 有用,可以幫助我們。關於這個軟體的更多資訊請見 %s。</translation>
</message>
<message>
+ <source>Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, &gt;%u = automatically prune block files to stay under the specified target size in MiB)</source>
+ <translation>修剪(刪除)掉老舊區塊以降低需要的儲存空間。這樣會增加一個 RPC 指令 pruneblockchain,可以使用它來刪除指定的區塊;也可以指定目標儲存空間大小,以啟用對老舊區塊的自動修剪功能。這個模式跟 -txindex 和 -rescan 參數不相容。警告: 還原回不修剪模式會需要重新下載一整個區塊鏈。(預設值: 0 表示不修剪區塊,1 表示允許使用 RPC 指令做修剪,&gt;%u 的值表示為區塊資料的目標大小,單位是百萬位元組,MiB)</translation>
+ </message>
+ <message>
+ <source>Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)</source>
+ <translation>設定製造區塊時,所要包含交易每千位元組的最低手續費(單位是 %s)。(預設值: %s)</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 表示程式自動決定,小於 0 表示保留處理器核心不用的數目,預設值: %d)</translation>
</message>
@@ -3123,6 +3147,10 @@
<translation>是否要使用「通用即插即用」協定(UPnP),來設定聽候連線的通訊埠的對應(預設值: 當有聽候連線且沒有指定 -proxy 參數時為 1)</translation>
</message>
<message>
+ <source>Username and hashed password for JSON-RPC connections. The field &lt;userpw&gt; comes in the format: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=&lt;USERNAME&gt;/rpcpassword=&lt;PASSWORD&gt; pair of arguments. This option can be specified multiple times</source>
+ <translation>JSON-RPC 連線要用的使用者名稱和雜湊密碼。&lt;userpw&gt; 的格式是:&lt;使用者名稱&gt;:&lt;調味值&gt;$&lt;雜湊值&gt;。在 share/rpcuser 目錄下有一個示範的 python 程式。之後客戶端程式就可以用這對參數正常連線:rpcuser=&lt;使用者名稱&gt; 和 rpcpassword=&lt;密碼&gt;。這個選項可以給很多次。</translation>
+ </message>
+ <message>
<source>Wallet will not create transactions that violate mempool chain limits (default: %u)</source>
<translation>錢包軟體不會產生違反記憶池交易鏈限制的交易(預設值: %u)</translation>
</message>
@@ -3368,7 +3396,7 @@
</message>
<message>
<source>Use the test chain</source>
- <translation>使用測試鏈</translation>
+ <translation>使用測試區塊鏈</translation>
</message>
<message>
<source>User Agent comment (%s) contains unsafe characters.</source>
diff --git a/src/qt/macdockiconhandler.mm b/src/qt/macdockiconhandler.mm
index a41d39d51e..9e7de0f98f 100644
--- a/src/qt/macdockiconhandler.mm
+++ b/src/qt/macdockiconhandler.mm
@@ -18,7 +18,7 @@
extern void qt_mac_set_dock_menu(QMenu *);
#endif
-static MacDockIconHandler *s_instance = NULL;
+static MacDockIconHandler *s_instance = nullptr;
bool dockClickHandler(id self,SEL _cmd,...) {
Q_UNUSED(self)
@@ -34,7 +34,7 @@ void setupDockClickHandler() {
Class cls = objc_getClass("NSApplication");
id appInst = objc_msgSend((id)cls, sel_registerName("sharedApplication"));
- if (appInst != NULL) {
+ if (appInst != nullptr) {
id delegate = objc_msgSend(appInst, sel_registerName("delegate"));
Class delClass = (Class)objc_msgSend(delegate, sel_registerName("class"));
SEL shouldHandle = sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:");
@@ -53,7 +53,7 @@ MacDockIconHandler::MacDockIconHandler() : QObject()
setupDockClickHandler();
this->m_dummyWidget = new QWidget();
this->m_dockMenu = new QMenu(this->m_dummyWidget);
- this->setMainWindow(NULL);
+ this->setMainWindow(nullptr);
#if QT_VERSION < 0x050000
qt_mac_set_dock_menu(this->m_dockMenu);
#elif QT_VERSION >= 0x050200
@@ -69,7 +69,7 @@ void MacDockIconHandler::setMainWindow(QMainWindow *window) {
MacDockIconHandler::~MacDockIconHandler()
{
delete this->m_dummyWidget;
- this->setMainWindow(NULL);
+ this->setMainWindow(nullptr);
}
QMenu *MacDockIconHandler::dockMenu()
diff --git a/src/qt/macnotificationhandler.h b/src/qt/macnotificationhandler.h
index d4749b3d5f..3a005c3c46 100644
--- a/src/qt/macnotificationhandler.h
+++ b/src/qt/macnotificationhandler.h
@@ -7,20 +7,17 @@
#include <QObject>
-/** Macintosh-specific notification handler (supports UserNotificationCenter and Growl).
+/** Macintosh-specific notification handler (supports UserNotificationCenter).
*/
class MacNotificationHandler : public QObject
{
Q_OBJECT
public:
- /** shows a 10.8+ UserNotification in the UserNotificationCenter
+ /** shows a macOS 10.8+ UserNotification in the UserNotificationCenter
*/
void showNotification(const QString &title, const QString &text);
- /** executes AppleScript */
- void sendAppleScript(const QString &script);
-
/** check if OS can handle UserNotifications */
bool hasUserNotificationCenterSupport(void);
static MacNotificationHandler *instance();
diff --git a/src/qt/macnotificationhandler.mm b/src/qt/macnotificationhandler.mm
index dd3f622818..1b16c5f524 100644
--- a/src/qt/macnotificationhandler.mm
+++ b/src/qt/macnotificationhandler.mm
@@ -47,20 +47,6 @@ void MacNotificationHandler::showNotification(const QString &title, const QStrin
}
}
-// sendAppleScript just take a QString and executes it as apple script
-void MacNotificationHandler::sendAppleScript(const QString &script)
-{
- QByteArray utf8 = script.toUtf8();
- char* cString = (char *)utf8.constData();
- NSString *scriptApple = [[NSString alloc] initWithUTF8String:cString];
-
- NSAppleScript *as = [[NSAppleScript alloc] initWithSource:scriptApple];
- NSDictionary *err = nil;
- [as executeAndReturnError:&err];
- [as release];
- [scriptApple release];
-}
-
bool MacNotificationHandler::hasUserNotificationCenterSupport(void)
{
Class possibleClass = NSClassFromString(@"NSUserNotificationCenter");
@@ -75,7 +61,7 @@ bool MacNotificationHandler::hasUserNotificationCenterSupport(void)
MacNotificationHandler *MacNotificationHandler::instance()
{
- static MacNotificationHandler *s_instance = NULL;
+ static MacNotificationHandler *s_instance = nullptr;
if (!s_instance) {
s_instance = new MacNotificationHandler();
diff --git a/src/qt/modaloverlay.cpp b/src/qt/modaloverlay.cpp
index 89fb159956..e32a0bdda8 100644
--- a/src/qt/modaloverlay.cpp
+++ b/src/qt/modaloverlay.cpp
@@ -7,6 +7,8 @@
#include "guiutil.h"
+#include "chainparams.h"
+
#include <QResizeEvent>
#include <QPropertyAnimation>
@@ -80,36 +82,38 @@ void ModalOverlay::tipUpdate(int count, const QDateTime& blockDate, double nVeri
blockProcessTime.push_front(qMakePair(currentDate.toMSecsSinceEpoch(), nVerificationProgress));
// show progress speed if we have more then one sample
- if (blockProcessTime.size() >= 2)
- {
- double progressStart = blockProcessTime[0].second;
+ if (blockProcessTime.size() >= 2) {
double progressDelta = 0;
double progressPerHour = 0;
qint64 timeDelta = 0;
qint64 remainingMSecs = 0;
double remainingProgress = 1.0 - nVerificationProgress;
- for (int i = 1; i < blockProcessTime.size(); i++)
- {
+ for (int i = 1; i < blockProcessTime.size(); i++) {
QPair<qint64, double> sample = blockProcessTime[i];
// take first sample after 500 seconds or last available one
if (sample.first < (currentDate.toMSecsSinceEpoch() - 500 * 1000) || i == blockProcessTime.size() - 1) {
- progressDelta = progressStart-sample.second;
+ progressDelta = blockProcessTime[0].second - sample.second;
timeDelta = blockProcessTime[0].first - sample.first;
- progressPerHour = progressDelta/(double)timeDelta*1000*3600;
- remainingMSecs = remainingProgress / progressDelta * timeDelta;
+ progressPerHour = progressDelta / (double) timeDelta * 1000 * 3600;
+ remainingMSecs = (progressDelta > 0) ? remainingProgress / progressDelta * timeDelta : -1;
break;
}
}
// show progress increase per hour
- ui->progressIncreasePerH->setText(QString::number(progressPerHour*100, 'f', 2)+"%");
+ ui->progressIncreasePerH->setText(QString::number(progressPerHour * 100, 'f', 2)+"%");
// show expected remaining time
- ui->expectedTimeLeft->setText(GUIUtil::formatNiceTimeOffset(remainingMSecs/1000.0));
+ if(remainingMSecs >= 0) {
+ ui->expectedTimeLeft->setText(GUIUtil::formatNiceTimeOffset(remainingMSecs / 1000.0));
+ } else {
+ ui->expectedTimeLeft->setText(QObject::tr("unknown"));
+ }
static const int MAX_SAMPLES = 5000;
- if (blockProcessTime.count() > MAX_SAMPLES)
- blockProcessTime.remove(MAX_SAMPLES, blockProcessTime.count()-MAX_SAMPLES);
+ if (blockProcessTime.count() > MAX_SAMPLES) {
+ blockProcessTime.remove(MAX_SAMPLES, blockProcessTime.count() - MAX_SAMPLES);
+ }
}
// show the last block date
@@ -124,12 +128,12 @@ void ModalOverlay::tipUpdate(int count, const QDateTime& blockDate, double nVeri
return;
// estimate the number of headers left based on nPowTargetSpacing
- // and check if the gui is not aware of the the best header (happens rarely)
- int estimateNumHeadersLeft = bestHeaderDate.secsTo(currentDate) / 600;
+ // and check if the gui is not aware of the best header (happens rarely)
+ int estimateNumHeadersLeft = bestHeaderDate.secsTo(currentDate) / Params().GetConsensus().nPowTargetSpacing;
bool hasBestHeader = bestHeaderHeight >= count;
// show remaining number of blocks
- if (estimateNumHeadersLeft < 24 && hasBestHeader) {
+ if (estimateNumHeadersLeft < HEADER_HEIGHT_DELTA_SYNC && hasBestHeader) {
ui->numberOfBlocksLeft->setText(QString::number(bestHeaderHeight - count));
} else {
ui->numberOfBlocksLeft->setText(tr("Unknown. Syncing Headers (%1)...").arg(bestHeaderHeight));
diff --git a/src/qt/modaloverlay.h b/src/qt/modaloverlay.h
index 70d37b87ad..cda23f9540 100644
--- a/src/qt/modaloverlay.h
+++ b/src/qt/modaloverlay.h
@@ -8,6 +8,9 @@
#include <QDateTime>
#include <QWidget>
+//! The required delta of headers to the estimated number of available headers until we show the IBD progress
+static constexpr int HEADER_HEIGHT_DELTA_SYNC = 24;
+
namespace Ui {
class ModalOverlay;
}
@@ -29,7 +32,7 @@ public Q_SLOTS:
// will show or hide the modal layer
void showHide(bool hide = false, bool userRequested = false);
void closeClicked();
- bool isLayerVisible() { return layerIsVisible; }
+ bool isLayerVisible() const { return layerIsVisible; }
protected:
bool eventFilter(QObject * obj, QEvent * ev);
diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp
index 93092501c9..4b81c54d36 100644
--- a/src/qt/networkstyle.cpp
+++ b/src/qt/networkstyle.cpp
@@ -44,7 +44,7 @@ NetworkStyle::NetworkStyle(const QString &_appName, const int iconColorHueShift,
// loop through pixels
for(int x=0;x<img.width();x++)
{
- // preserve alpha because QColor::getHsl doesen't return the alpha value
+ // preserve alpha because QColor::getHsl doesn't return the alpha value
a = qAlpha(scL[x]);
QColor col(scL[x]);
diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp
index 8718929c6a..937928315b 100644
--- a/src/qt/notificator.cpp
+++ b/src/qt/notificator.cpp
@@ -60,22 +60,6 @@ Notificator::Notificator(const QString &_programName, QSystemTrayIcon *_trayIcon
if( MacNotificationHandler::instance()->hasUserNotificationCenterSupport()) {
mode = UserNotificationCenter;
}
- else {
- // Check if Growl is installed (based on Qt's tray icon implementation)
- CFURLRef cfurl;
- OSStatus status = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, CFSTR("growlTicket"), kLSRolesAll, 0, &cfurl);
- if (status != kLSApplicationNotFoundErr) {
- CFBundleRef bundle = CFBundleCreate(0, cfurl);
- if (CFStringCompare(CFBundleGetIdentifier(bundle), CFSTR("com.Growl.GrowlHelperApp"), kCFCompareCaseInsensitive | kCFCompareBackwards) == kCFCompareEqualTo) {
- if (CFStringHasSuffix(CFURLGetString(cfurl), CFSTR("/Growl.app/")))
- mode = Growl13;
- else
- mode = Growl12;
- }
- CFRelease(cfurl);
- CFRelease(bundle);
- }
- }
#endif
}
@@ -93,7 +77,7 @@ class FreedesktopImage
{
public:
FreedesktopImage() {}
- FreedesktopImage(const QImage &img);
+ explicit FreedesktopImage(const QImage &img);
static int metaType();
@@ -241,52 +225,6 @@ void Notificator::notifySystray(Class cls, const QString &title, const QString &
// Based on Qt's tray icon implementation
#ifdef Q_OS_MAC
-void Notificator::notifyGrowl(Class cls, const QString &title, const QString &text, const QIcon &icon)
-{
- const QString script(
- "tell application \"%5\"\n"
- " set the allNotificationsList to {\"Notification\"}\n" // -- Make a list of all the notification types (all)
- " set the enabledNotificationsList to {\"Notification\"}\n" // -- Make a list of the notifications (enabled)
- " register as application \"%1\" all notifications allNotificationsList default notifications enabledNotificationsList\n" // -- Register our script with Growl
- " notify with name \"Notification\" title \"%2\" description \"%3\" application name \"%1\"%4\n" // -- Send a Notification
- "end tell"
- );
-
- QString notificationApp(QApplication::applicationName());
- if (notificationApp.isEmpty())
- notificationApp = "Application";
-
- QPixmap notificationIconPixmap;
- if (icon.isNull()) { // If no icon specified, set icon based on class
- QStyle::StandardPixmap sicon = QStyle::SP_MessageBoxQuestion;
- switch (cls)
- {
- case Information: sicon = QStyle::SP_MessageBoxInformation; break;
- case Warning: sicon = QStyle::SP_MessageBoxWarning; break;
- case Critical: sicon = QStyle::SP_MessageBoxCritical; break;
- }
- notificationIconPixmap = QApplication::style()->standardPixmap(sicon);
- }
- else {
- QSize size = icon.actualSize(QSize(48, 48));
- notificationIconPixmap = icon.pixmap(size);
- }
-
- QString notificationIcon;
- QTemporaryFile notificationIconFile;
- if (!notificationIconPixmap.isNull() && notificationIconFile.open()) {
- QImageWriter writer(&notificationIconFile, "PNG");
- if (writer.write(notificationIconPixmap.toImage()))
- notificationIcon = QString(" image from location \"file://%1\"").arg(notificationIconFile.fileName());
- }
-
- QString quotedTitle(title), quotedText(text);
- quotedTitle.replace("\\", "\\\\").replace("\"", "\\");
- quotedText.replace("\\", "\\\\").replace("\"", "\\");
- QString growlApp(this->mode == Notificator::Growl13 ? "Growl" : "GrowlHelperApp");
- MacNotificationHandler::instance()->sendAppleScript(script.arg(notificationApp, quotedTitle, quotedText, notificationIcon, growlApp));
-}
-
void Notificator::notifyMacUserNotificationCenter(Class cls, const QString &title, const QString &text, const QIcon &icon) {
// icon is not supported by the user notification center yet. OSX will use the app icon.
MacNotificationHandler::instance()->showNotification(title, text);
@@ -310,10 +248,6 @@ void Notificator::notify(Class cls, const QString &title, const QString &text, c
case UserNotificationCenter:
notifyMacUserNotificationCenter(cls, title, text, icon);
break;
- case Growl12:
- case Growl13:
- notifyGrowl(cls, title, text, icon);
- break;
#endif
default:
if(cls == Critical)
diff --git a/src/qt/notificator.h b/src/qt/notificator.h
index f92b791d4a..67f2b1df69 100644
--- a/src/qt/notificator.h
+++ b/src/qt/notificator.h
@@ -58,8 +58,6 @@ private:
None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */
Freedesktop, /**< Use DBus org.freedesktop.Notifications */
QSystemTray, /**< Use QSystemTray::showMessage */
- Growl12, /**< Use the Growl 1.2 notification system (Mac only) */
- Growl13, /**< Use the Growl 1.3 notification system (Mac only) */
UserNotificationCenter /**< Use the 10.8+ User Notification Center (Mac only) */
};
QString programName;
@@ -72,7 +70,6 @@ private:
#endif
void notifySystray(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout);
#ifdef Q_OS_MAC
- void notifyGrowl(Class cls, const QString &title, const QString &text, const QIcon &icon);
void notifyMacUserNotificationCenter(Class cls, const QString &title, const QString &text, const QIcon &icon);
#endif
};
diff --git a/src/qt/openuridialog.cpp b/src/qt/openuridialog.cpp
index 5a66161346..3ee656d470 100644
--- a/src/qt/openuridialog.cpp
+++ b/src/qt/openuridialog.cpp
@@ -44,7 +44,7 @@ void OpenURIDialog::accept()
void OpenURIDialog::on_selectFileButton_clicked()
{
- QString filename = GUIUtil::getOpenFileName(this, tr("Select payment request file to open"), "", "", NULL);
+ QString filename = GUIUtil::getOpenFileName(this, tr("Select payment request file to open"), "", "", nullptr);
if(filename.isEmpty())
return;
QUrl fileUri = QUrl::fromLocalFile(filename);
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index 89f633aa73..53e2e5053c 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -17,12 +17,6 @@
#include "netbase.h"
#include "txdb.h" // for -dbcache defaults
-#ifdef ENABLE_WALLET
-#include "wallet/wallet.h" // for CWallet::GetRequiredFee()
-#endif
-
-#include <boost/thread.hpp>
-
#include <QDataWidgetMapper>
#include <QDir>
#include <QIntValidator>
@@ -82,9 +76,11 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
ui->bitcoinAtStartup->setToolTip(ui->bitcoinAtStartup->toolTip().arg(tr(PACKAGE_NAME)));
ui->bitcoinAtStartup->setText(ui->bitcoinAtStartup->text().arg(tr(PACKAGE_NAME)));
+ ui->openBitcoinConfButton->setToolTip(ui->openBitcoinConfButton->toolTip().arg(tr(PACKAGE_NAME)));
+
ui->lang->setToolTip(ui->lang->toolTip().arg(tr(PACKAGE_NAME)));
ui->lang->addItem(QString("(") + tr("default") + QString(")"), QVariant(""));
- Q_FOREACH(const QString &langStr, translations.entryList())
+ for (const QString &langStr : translations.entryList())
{
QLocale locale(langStr);
@@ -232,6 +228,18 @@ void OptionsDialog::on_resetButton_clicked()
}
}
+void OptionsDialog::on_openBitcoinConfButton_clicked()
+{
+ /* explain the purpose of the config file */
+ QMessageBox::information(this, tr("Configuration options"),
+ tr("The configuration file is used to specify advanced user options which override GUI settings. "
+ "Additionally, any command-line options will override this configuration file."));
+
+ /* show an error if there was some problem opening the file */
+ if (!GUIUtil::openBitcoinConf())
+ QMessageBox::critical(this, tr("Error"), tr("The configuration file could not be opened."));
+}
+
void OptionsDialog::on_okButton_clicked()
{
mapper->submit();
@@ -277,6 +285,9 @@ void OptionsDialog::showRestartWarning(bool fPersistent)
void OptionsDialog::clearStatusLabel()
{
ui->statusLabel->clear();
+ if (model && model->isRestartRequired()) {
+ showRestartWarning(true);
+ }
}
void OptionsDialog::updateProxyValidationState()
@@ -286,7 +297,7 @@ void OptionsDialog::updateProxyValidationState()
if (pUiProxyIp->isValid() && (!ui->proxyPort->isEnabled() || ui->proxyPort->text().toInt() > 0) && (!ui->proxyPortTor->isEnabled() || ui->proxyPortTor->text().toInt() > 0))
{
setOkButtonState(otherProxyWidget->isValid()); //only enable ok button if both proxys are valid
- ui->statusLabel->clear();
+ clearStatusLabel();
}
else
{
diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h
index d98c1dc193..f9f5823c05 100644
--- a/src/qt/optionsdialog.h
+++ b/src/qt/optionsdialog.h
@@ -47,6 +47,7 @@ private Q_SLOTS:
/* set OK button state (enabled / disabled) */
void setOkButtonState(bool fState);
void on_resetButton_clicked();
+ void on_openBitcoinConfButton_clicked();
void on_okButton_clicked();
void on_cancelButton_clicked();
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index d6e740ee9c..feb00a33b0 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -36,7 +36,7 @@ OptionsModel::OptionsModel(QObject *parent, bool resetSettings) :
void OptionsModel::addOverriddenOption(const std::string &option)
{
- strOverriddenByCommandLine += QString::fromStdString(option) + "=" + QString::fromStdString(GetArg(option, "")) + " ";
+ strOverriddenByCommandLine += QString::fromStdString(option) + "=" + QString::fromStdString(gArgs.GetArg(option, "")) + " ";
}
// Writes all missing QSettings with their default values
@@ -86,18 +86,18 @@ void OptionsModel::Init(bool resetSettings)
//
// If setting doesn't exist create it with defaults.
//
- // If SoftSetArg() or SoftSetBoolArg() return false we were overridden
+ // If gArgs.SoftSetArg() or gArgs.SoftSetBoolArg() return false we were overridden
// by command-line and show this in the UI.
// Main
if (!settings.contains("nDatabaseCache"))
settings.setValue("nDatabaseCache", (qint64)nDefaultDbCache);
- if (!SoftSetArg("-dbcache", settings.value("nDatabaseCache").toString().toStdString()))
+ if (!gArgs.SoftSetArg("-dbcache", settings.value("nDatabaseCache").toString().toStdString()))
addOverriddenOption("-dbcache");
if (!settings.contains("nThreadsScriptVerif"))
settings.setValue("nThreadsScriptVerif", DEFAULT_SCRIPTCHECK_THREADS);
- if (!SoftSetArg("-par", settings.value("nThreadsScriptVerif").toString().toStdString()))
+ if (!gArgs.SoftSetArg("-par", settings.value("nThreadsScriptVerif").toString().toStdString()))
addOverriddenOption("-par");
if (!settings.contains("strDataDir"))
@@ -107,19 +107,19 @@ void OptionsModel::Init(bool resetSettings)
#ifdef ENABLE_WALLET
if (!settings.contains("bSpendZeroConfChange"))
settings.setValue("bSpendZeroConfChange", true);
- if (!SoftSetBoolArg("-spendzeroconfchange", settings.value("bSpendZeroConfChange").toBool()))
+ if (!gArgs.SoftSetBoolArg("-spendzeroconfchange", settings.value("bSpendZeroConfChange").toBool()))
addOverriddenOption("-spendzeroconfchange");
#endif
// Network
if (!settings.contains("fUseUPnP"))
settings.setValue("fUseUPnP", DEFAULT_UPNP);
- if (!SoftSetBoolArg("-upnp", settings.value("fUseUPnP").toBool()))
+ if (!gArgs.SoftSetBoolArg("-upnp", settings.value("fUseUPnP").toBool()))
addOverriddenOption("-upnp");
if (!settings.contains("fListen"))
settings.setValue("fListen", DEFAULT_LISTEN);
- if (!SoftSetBoolArg("-listen", settings.value("fListen").toBool()))
+ if (!gArgs.SoftSetBoolArg("-listen", settings.value("fListen").toBool()))
addOverriddenOption("-listen");
if (!settings.contains("fUseProxy"))
@@ -127,9 +127,9 @@ void OptionsModel::Init(bool resetSettings)
if (!settings.contains("addrProxy"))
settings.setValue("addrProxy", "127.0.0.1:9050");
// Only try to set -proxy, if user has enabled fUseProxy
- if (settings.value("fUseProxy").toBool() && !SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString()))
+ if (settings.value("fUseProxy").toBool() && !gArgs.SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString()))
addOverriddenOption("-proxy");
- else if(!settings.value("fUseProxy").toBool() && !GetArg("-proxy", "").empty())
+ else if(!settings.value("fUseProxy").toBool() && !gArgs.GetArg("-proxy", "").empty())
addOverriddenOption("-proxy");
if (!settings.contains("fUseSeparateProxyTor"))
@@ -137,24 +137,46 @@ void OptionsModel::Init(bool resetSettings)
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()))
+ if (settings.value("fUseSeparateProxyTor").toBool() && !gArgs.SoftSetArg("-onion", settings.value("addrSeparateProxyTor").toString().toStdString()))
addOverriddenOption("-onion");
- else if(!settings.value("fUseSeparateProxyTor").toBool() && !GetArg("-onion", "").empty())
+ else if(!settings.value("fUseSeparateProxyTor").toBool() && !gArgs.GetArg("-onion", "").empty())
addOverriddenOption("-onion");
// Display
if (!settings.contains("language"))
settings.setValue("language", "");
- if (!SoftSetArg("-lang", settings.value("language").toString().toStdString()))
+ if (!gArgs.SoftSetArg("-lang", settings.value("language").toString().toStdString()))
addOverriddenOption("-lang");
language = settings.value("language").toString();
}
+/** Helper function to copy contents from one QSettings to another.
+ * By using allKeys this also covers nested settings in a hierarchy.
+ */
+static void CopySettings(QSettings& dst, const QSettings& src)
+{
+ for (const QString& key : src.allKeys()) {
+ dst.setValue(key, src.value(key));
+ }
+}
+
+/** Back up a QSettings to an ini-formatted file. */
+static void BackupSettings(const fs::path& filename, const QSettings& src)
+{
+ qWarning() << "Backing up GUI settings to" << GUIUtil::boostPathToQString(filename);
+ QSettings dst(GUIUtil::boostPathToQString(filename), QSettings::IniFormat);
+ dst.clear();
+ CopySettings(dst, src);
+}
+
void OptionsModel::Reset()
{
QSettings settings;
+ // Backup old settings to chain-specific datadir for troubleshooting
+ BackupSettings(GetDataDir(true) / "guisettings.ini.bak", settings);
+
// Save the strDataDir setting
QString dataDir = Intro::getDefaultDataDirectory();
dataDir = settings.value("strDataDir", dataDir).toString();
@@ -441,7 +463,7 @@ void OptionsModel::setRestartRequired(bool fRequired)
return settings.setValue("fRestartRequired", fRequired);
}
-bool OptionsModel::isRestartRequired()
+bool OptionsModel::isRestartRequired() const
{
QSettings settings;
return settings.value("fRestartRequired", false).toBool();
diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h
index 78529fbdcc..0ac82a4148 100644
--- a/src/qt/optionsmodel.h
+++ b/src/qt/optionsmodel.h
@@ -59,18 +59,18 @@ public:
void setDisplayUnit(const QVariant &value);
/* Explicit getters */
- bool getHideTrayIcon() { return fHideTrayIcon; }
- bool getMinimizeToTray() { return fMinimizeToTray; }
- bool getMinimizeOnClose() { return fMinimizeOnClose; }
- int getDisplayUnit() { return nDisplayUnit; }
- QString getThirdPartyTxUrls() { return strThirdPartyTxUrls; }
+ bool getHideTrayIcon() const { return fHideTrayIcon; }
+ bool getMinimizeToTray() const { return fMinimizeToTray; }
+ bool getMinimizeOnClose() const { return fMinimizeOnClose; }
+ int getDisplayUnit() const { return nDisplayUnit; }
+ QString getThirdPartyTxUrls() const { return strThirdPartyTxUrls; }
bool getProxySettings(QNetworkProxy& proxy) const;
- bool getCoinControlFeatures() { return fCoinControlFeatures; }
+ bool getCoinControlFeatures() const { return fCoinControlFeatures; }
const QString& getOverriddenByCommandLine() { return strOverriddenByCommandLine; }
/* Restart flag helper */
void setRestartRequired(bool fRequired);
- bool isRestartRequired();
+ bool isRestartRequired() const;
private:
/* Qt-only settings */
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index ba344f4dbf..ba1839e7b4 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -25,7 +25,7 @@ class TxViewDelegate : public QAbstractItemDelegate
{
Q_OBJECT
public:
- TxViewDelegate(const PlatformStyle *_platformStyle, QObject *parent=nullptr):
+ explicit TxViewDelegate(const PlatformStyle *_platformStyle, QObject *parent=nullptr):
QAbstractItemDelegate(parent), unit(BitcoinUnits::BTC),
platformStyle(_platformStyle)
{
diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp
index 01ec416613..d3799f59ab 100644
--- a/src/qt/paymentrequestplus.cpp
+++ b/src/qt/paymentrequestplus.cpp
@@ -22,7 +22,7 @@
class SSLVerifyError : public std::runtime_error
{
public:
- SSLVerifyError(std::string err) : std::runtime_error(err) { }
+ explicit SSLVerifyError(std::string err) : std::runtime_error(err) { }
};
bool PaymentRequestPlus::parse(const QByteArray& data)
@@ -66,7 +66,7 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c
// One day we'll support more PKI types, but just
// x509 for now:
- const EVP_MD* digestAlgorithm = NULL;
+ const EVP_MD* digestAlgorithm = nullptr;
if (paymentRequest.pki_type() == "x509+sha256") {
digestAlgorithm = EVP_sha256();
}
@@ -104,7 +104,7 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c
}
#endif
const unsigned char *data = (const unsigned char *)certChain.certificate(i).data();
- X509 *cert = d2i_X509(NULL, &data, certChain.certificate(i).size());
+ X509 *cert = d2i_X509(nullptr, &data, certChain.certificate(i).size());
if (cert)
certs.push_back(cert);
}
@@ -129,7 +129,7 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c
return false;
}
- char *website = NULL;
+ char *website = nullptr;
bool fResult = true;
try
{
@@ -145,7 +145,7 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c
int error = X509_STORE_CTX_get_error(store_ctx);
// For testing payment requests, we allow self signed root certs!
// This option is just shown in the UI options, if -help-debug is enabled.
- if (!(error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT && GetBoolArg("-allowselfsignedrootcertificates", DEFAULT_SELFSIGNED_ROOTCERTS))) {
+ if (!(error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT && gArgs.GetBoolArg("-allowselfsignedrootcertificates", DEFAULT_SELFSIGNED_ROOTCERTS))) {
throw SSLVerifyError(X509_verify_cert_error_string(error));
} else {
qDebug() << "PaymentRequestPlus::getMerchant: Allowing self signed root certificate, because -allowselfsignedrootcertificates is true.";
@@ -169,7 +169,7 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c
#endif
EVP_PKEY *pubkey = X509_get_pubkey(signing_cert);
EVP_MD_CTX_init(ctx);
- if (!EVP_VerifyInit_ex(ctx, digestAlgorithm, NULL) ||
+ if (!EVP_VerifyInit_ex(ctx, digestAlgorithm, nullptr) ||
!EVP_VerifyUpdate(ctx, data_to_verify.data(), data_to_verify.size()) ||
!EVP_VerifyFinal(ctx, (const unsigned char*)paymentRequest.signature().data(), (unsigned int)paymentRequest.signature().size(), pubkey)) {
throw SSLVerifyError("Bad signature, invalid payment request.");
@@ -179,7 +179,7 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c
#endif
// OpenSSL API for getting human printable strings from certs is baroque.
- int textlen = X509_NAME_get_text_by_NID(certname, NID_commonName, NULL, 0);
+ int textlen = X509_NAME_get_text_by_NID(certname, NID_commonName, nullptr, 0);
website = new char[textlen + 1];
if (X509_NAME_get_text_by_NID(certname, NID_commonName, website, textlen + 1) == textlen && textlen > 0) {
merchant = website;
diff --git a/src/qt/paymentrequestplus.h b/src/qt/paymentrequestplus.h
index ee1a37d83c..a2fea3fdc6 100644
--- a/src/qt/paymentrequestplus.h
+++ b/src/qt/paymentrequestplus.h
@@ -5,7 +5,10 @@
#ifndef BITCOIN_QT_PAYMENTREQUESTPLUS_H
#define BITCOIN_QT_PAYMENTREQUESTPLUS_H
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#include "paymentrequest.pb.h"
+#pragma GCC diagnostic pop
#include "base58.h"
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 688e8123af..169684cf6d 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -55,8 +55,6 @@ const char* BIP70_MESSAGE_PAYMENTREQUEST = "PaymentRequest";
const char* BIP71_MIMETYPE_PAYMENT = "application/bitcoin-payment";
const char* BIP71_MIMETYPE_PAYMENTACK = "application/bitcoin-paymentack";
const char* BIP71_MIMETYPE_PAYMENTREQUEST = "application/bitcoin-paymentrequest";
-// BIP70 max payment request size in bytes (DoS protection)
-const qint64 BIP70_MAX_PAYMENTREQUEST_SIZE = 50000;
struct X509StoreDeleter {
void operator()(X509_STORE* b) {
@@ -124,7 +122,7 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store)
// Note: use "-system-" default here so that users can pass -rootcertificates=""
// and get 'I don't like X.509 certificates, don't trust anybody' behavior:
- QString certFile = QString::fromStdString(GetArg("-rootcertificates", "-system-"));
+ QString certFile = QString::fromStdString(gArgs.GetArg("-rootcertificates", "-system-"));
// Empty store
if (certFile.isEmpty()) {
@@ -146,7 +144,7 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store)
int nRootCerts = 0;
const QDateTime currentTime = QDateTime::currentDateTime();
- Q_FOREACH (const QSslCertificate& cert, certList) {
+ for (const QSslCertificate& cert : certList) {
// Don't log NULL certificates
if (cert.isNull())
continue;
@@ -220,15 +218,15 @@ void PaymentServer::ipcParseCommandLine(int argc, char* argv[])
SendCoinsRecipient r;
if (GUIUtil::parseBitcoinURI(arg, &r) && !r.address.isEmpty())
{
- CBitcoinAddress address(r.address.toStdString());
+ auto tempChainParams = CreateChainParams(CBaseChainParams::MAIN);
- if (address.IsValid(Params(CBaseChainParams::MAIN)))
- {
+ if (IsValidDestinationString(r.address.toStdString(), *tempChainParams)) {
SelectParams(CBaseChainParams::MAIN);
- }
- else if (address.IsValid(Params(CBaseChainParams::TESTNET)))
- {
- SelectParams(CBaseChainParams::TESTNET);
+ } else {
+ tempChainParams = CreateChainParams(CBaseChainParams::TESTNET);
+ if (IsValidDestinationString(r.address.toStdString(), *tempChainParams)) {
+ SelectParams(CBaseChainParams::TESTNET);
+ }
}
}
}
@@ -267,14 +265,14 @@ void PaymentServer::ipcParseCommandLine(int argc, char* argv[])
bool PaymentServer::ipcSendCommandLine()
{
bool fResult = false;
- Q_FOREACH (const QString& r, savedPaymentRequests)
+ for (const QString& r : savedPaymentRequests)
{
QLocalSocket* socket = new QLocalSocket();
socket->connectToServer(ipcServerName(), QIODevice::WriteOnly);
if (!socket->waitForConnected(BITCOIN_IPC_CONNECT_TIMEOUT))
{
delete socket;
- socket = NULL;
+ socket = nullptr;
return false;
}
@@ -290,7 +288,7 @@ bool PaymentServer::ipcSendCommandLine()
socket->disconnectFromServer();
delete socket;
- socket = NULL;
+ socket = nullptr;
fResult = true;
}
@@ -364,7 +362,7 @@ void PaymentServer::initNetManager()
{
if (!optionsModel)
return;
- if (netManager != NULL)
+ if (netManager != nullptr)
delete netManager;
// netManager is used to fetch paymentrequests given in bitcoin: URIs
@@ -392,7 +390,7 @@ void PaymentServer::uiReady()
initNetManager();
saveURIs = false;
- Q_FOREACH (const QString& s, savedPaymentRequests)
+ for (const QString& s : savedPaymentRequests)
{
handleURIOrFile(s);
}
@@ -441,8 +439,7 @@ void PaymentServer::handleURIOrFile(const QString& s)
SendCoinsRecipient recipient;
if (GUIUtil::parseBitcoinURI(s, &recipient))
{
- CBitcoinAddress address(recipient.address.toStdString());
- if (!address.IsValid()) {
+ if (!IsValidDestinationString(recipient.address.toStdString())) {
Q_EMIT message(tr("URI handling"), tr("Invalid payment address %1").arg(recipient.address),
CClientUIInterface::MSG_ERROR);
}
@@ -555,12 +552,12 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
QList<std::pair<CScript, CAmount> > sendingTos = request.getPayTo();
QStringList addresses;
- Q_FOREACH(const PAIRTYPE(CScript, CAmount)& sendingTo, sendingTos) {
+ for (const std::pair<CScript, CAmount>& sendingTo : sendingTos) {
// Extract and check destination addresses
CTxDestination dest;
if (ExtractDestination(sendingTo.first, dest)) {
// Append destination address
- addresses.append(QString::fromStdString(CBitcoinAddress(dest).ToString()));
+ addresses.append(QString::fromStdString(EncodeDestination(dest)));
}
else if (!recipient.authenticatedMerchant.isEmpty()) {
// Unauthenticated payment requests to custom bitcoin addresses are not supported
@@ -582,7 +579,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
// Extract and check amounts
CTxOut txOut(sendingTo.second, sendingTo.first);
- if (txOut.IsDust(dustRelayFee)) {
+ if (IsDust(txOut, ::dustRelayFee)) {
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);
@@ -620,7 +617,7 @@ void PaymentServer::fetchRequest(const QUrl& url)
netManager->get(netRequest);
}
-void PaymentServer::fetchPaymentACK(CWallet* wallet, SendCoinsRecipient recipient, QByteArray transaction)
+void PaymentServer::fetchPaymentACK(CWallet* wallet, const SendCoinsRecipient& recipient, QByteArray transaction)
{
const payments::PaymentDetails& details = recipient.paymentRequest.getDetails();
if (!details.has_payment_url())
@@ -742,7 +739,7 @@ void PaymentServer::reportSslErrors(QNetworkReply* reply, const QList<QSslError>
Q_UNUSED(reply);
QString errString;
- Q_FOREACH (const QSslError& err, errs) {
+ for (const QSslError& err : errs) {
qWarning() << "PaymentServer::reportSslErrors: " << err;
errString += err.errorString() + "\n";
}
diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h
index 37ee522d54..98b2364b92 100644
--- a/src/qt/paymentserver.h
+++ b/src/qt/paymentserver.h
@@ -21,10 +21,10 @@
//
// When startup is finished and the main window is
// shown, a signal is sent to slot uiReady(), which
-// emits a receivedURL() signal for any payment
+// emits a receivedURI() signal for any payment
// requests that happened during startup.
//
-// After startup, receivedURL() happens as usual.
+// After startup, receivedURI() happens as usual.
//
// This class has one more feature: a static
// method that finds URIs passed in the command line
@@ -53,7 +53,7 @@ class QUrl;
QT_END_NAMESPACE
// BIP70 max payment request size in bytes (DoS protection)
-extern const qint64 BIP70_MAX_PAYMENTREQUEST_SIZE;
+static const qint64 BIP70_MAX_PAYMENTREQUEST_SIZE = 50000;
class PaymentServer : public QObject
{
@@ -72,15 +72,15 @@ public:
static bool ipcSendCommandLine();
// parent should be QApplication object
- PaymentServer(QObject* parent, bool startLocalServer = true);
+ explicit PaymentServer(QObject* parent, bool startLocalServer = true);
~PaymentServer();
- // Load root certificate authorities. Pass NULL (default)
+ // Load root certificate authorities. Pass nullptr (default)
// to read from the file specified in the -rootcertificates setting,
// or, if that's not set, to use the system default root certificates.
// If you pass in a store, you should not X509_STORE_free it: it will be
// freed either at exit or when another set of CAs are loaded.
- static void LoadRootCAs(X509_STORE* store = NULL);
+ static void LoadRootCAs(X509_STORE* store = nullptr);
// Return certificate store
static X509_STORE* getCertStore();
@@ -113,7 +113,7 @@ public Q_SLOTS:
void uiReady();
// Submit Payment message to a merchant, get back PaymentACK:
- void fetchPaymentACK(CWallet* wallet, SendCoinsRecipient recipient, QByteArray transaction);
+ void fetchPaymentACK(CWallet* wallet, const SendCoinsRecipient& recipient, QByteArray transaction);
// Handle an incoming URI, URI with local file scheme or file
void handleURIOrFile(const QString& s);
diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp
index 974a71ddca..42934f8055 100644
--- a/src/qt/peertablemodel.cpp
+++ b/src/qt/peertablemodel.cpp
@@ -62,7 +62,7 @@ public:
#if QT_VERSION >= 0x040700
cachedNodeStats.reserve(vstats.size());
#endif
- Q_FOREACH (const CNodeStats& nodestats, vstats)
+ for (const CNodeStats& nodestats : vstats)
{
CNodeCombinedStats stats;
stats.nodeStateStats.nMisbehavior = 0;
@@ -79,7 +79,7 @@ public:
TRY_LOCK(cs_main, lockMain);
if (lockMain)
{
- BOOST_FOREACH(CNodeCombinedStats &stats, cachedNodeStats)
+ for (CNodeCombinedStats &stats : cachedNodeStats)
stats.fNodeStateStatsAvailable = GetNodeStateStats(stats.nodeStats.nodeid, stats.nodeStateStats);
}
}
@@ -91,7 +91,7 @@ public:
// build index map
mapNodeRows.clear();
int row = 0;
- Q_FOREACH (const CNodeCombinedStats& stats, cachedNodeStats)
+ for (const CNodeCombinedStats& stats : cachedNodeStats)
mapNodeRows.insert(std::pair<NodeId, int>(stats.nodeStats.nodeid, row++));
}
@@ -166,7 +166,7 @@ QVariant PeerTableModel::data(const QModelIndex &index, int role) const
switch(index.column())
{
case NetNodeId:
- return rec->nodeStats.nodeid;
+ return (qint64)rec->nodeStats.nodeid;
case Address:
return QString::fromStdString(rec->nodeStats.addrName);
case Subversion:
diff --git a/src/qt/platformstyle.cpp b/src/qt/platformstyle.cpp
index 90bd619c04..1f4e1a442f 100644
--- a/src/qt/platformstyle.cpp
+++ b/src/qt/platformstyle.cpp
@@ -48,8 +48,7 @@ void MakeSingleColorImage(QImage& img, const QColor& colorbase)
QIcon ColorizeIcon(const QIcon& ico, const QColor& colorbase)
{
QIcon new_ico;
- QSize sz;
- Q_FOREACH(sz, ico.availableSizes())
+ for (const QSize sz : ico.availableSizes())
{
QImage img(ico.pixmap(sz).toImage());
MakeSingleColorImage(img, colorbase);
diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp
index e98f4d3347..84f43266e1 100644
--- a/src/qt/receivecoinsdialog.cpp
+++ b/src/qt/receivecoinsdialog.cpp
@@ -191,7 +191,7 @@ void ReceiveCoinsDialog::on_showRequestButton_clicked()
return;
QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
- Q_FOREACH (const QModelIndex& index, selection) {
+ for (const QModelIndex& index : selection) {
on_recentRequestsView_doubleClicked(index);
}
}
diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h
index 1d0491c0d5..385f98565c 100644
--- a/src/qt/receivecoinsdialog.h
+++ b/src/qt/receivecoinsdialog.h
@@ -15,7 +15,6 @@
#include <QPoint>
#include <QVariant>
-class OptionsModel;
class PlatformStyle;
class WalletModel;
diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp
index 3752fa4b66..4aa6375d8a 100644
--- a/src/qt/receiverequestdialog.cpp
+++ b/src/qt/receiverequestdialog.cpp
@@ -68,7 +68,7 @@ void QRImageWidget::saveImage()
{
if(!pixmap())
return;
- QString fn = GUIUtil::getSaveFileName(this, tr("Save QR Code"), QString(), tr("PNG Image (*.png)"), NULL);
+ QString fn = GUIUtil::getSaveFileName(this, tr("Save QR Code"), QString(), tr("PNG Image (*.png)"), nullptr);
if (!fn.isEmpty())
{
exportImage().save(fn);
diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp
index dac3979290..1c4f7aca86 100644
--- a/src/qt/recentrequeststablemodel.cpp
+++ b/src/qt/recentrequeststablemodel.cpp
@@ -11,7 +11,6 @@
#include "clientversion.h"
#include "streams.h"
-#include <boost/foreach.hpp>
RecentRequestsTableModel::RecentRequestsTableModel(CWallet *wallet, WalletModel *parent) :
QAbstractTableModel(parent), walletModel(parent)
@@ -22,7 +21,7 @@ RecentRequestsTableModel::RecentRequestsTableModel(CWallet *wallet, WalletModel
// Load entries from wallet
std::vector<std::string> vReceiveRequests;
parent->loadReceiveRequests(vReceiveRequests);
- BOOST_FOREACH(const std::string& request, vReceiveRequests)
+ for (const std::string& request : vReceiveRequests)
addNewRequest(request);
/* These columns must match the indices in the ColumnIndex enumeration */
@@ -55,10 +54,9 @@ QVariant RecentRequestsTableModel::data(const QModelIndex &index, int role) cons
if(!index.isValid() || index.row() >= list.length())
return QVariant();
- const RecentRequestEntry *rec = &list[index.row()];
-
if(role == Qt::DisplayRole || role == Qt::EditRole)
{
+ const RecentRequestEntry *rec = &list[index.row()];
switch(index.column())
{
case Date:
@@ -125,7 +123,7 @@ void RecentRequestsTableModel::updateAmountColumnTitle()
/** Gets title for amount column including current display unit if optionsModel reference available. */
QString RecentRequestsTableModel::getAmountTitle()
{
- return (this->walletModel->getOptionsModel() != NULL) ? tr("Requested") + " ("+BitcoinUnits::name(this->walletModel->getOptionsModel()->getDisplayUnit()) + ")" : "";
+ return (this->walletModel->getOptionsModel() != nullptr) ? tr("Requested") + " ("+BitcoinUnits::name(this->walletModel->getOptionsModel()->getDisplayUnit()) + ")" : "";
}
QModelIndex RecentRequestsTableModel::index(int row, int column, const QModelIndex &parent) const
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 87d73b5f08..d895fc1663 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -13,8 +13,6 @@
#include "clientmodel.h"
#include "guiutil.h"
#include "platformstyle.h"
-#include "bantablemodel.h"
-
#include "chainparams.h"
#include "netbase.h"
#include "rpc/server.h"
@@ -27,8 +25,10 @@
#ifdef ENABLE_WALLET
#include <db_cxx.h>
+#include <wallet/wallet.h>
#endif
+#include <QDesktopWidget>
#include <QKeyEvent>
#include <QMenu>
#include <QMessageBox>
@@ -61,7 +61,7 @@ const struct {
{"cmd-reply", ":/icons/tx_output"},
{"cmd-error", ":/icons/tx_output"},
{"misc", ":/icons/tx_inout"},
- {NULL, NULL}
+ {nullptr, nullptr}
};
namespace {
@@ -98,7 +98,7 @@ class QtRPCTimerBase: public QObject, public RPCTimerBase
{
Q_OBJECT
public:
- QtRPCTimerBase(boost::function<void(void)>& _func, int64_t millis):
+ QtRPCTimerBase(std::function<void(void)>& _func, int64_t millis):
func(_func)
{
timer.setSingleShot(true);
@@ -110,7 +110,7 @@ private Q_SLOTS:
void timeout() { func(); }
private:
QTimer timer;
- boost::function<void(void)> func;
+ std::function<void(void)> func;
};
class QtRPCTimerInterface: public RPCTimerInterface
@@ -118,7 +118,7 @@ class QtRPCTimerInterface: public RPCTimerInterface
public:
~QtRPCTimerInterface() {}
const char *Name() { return "Qt"; }
- RPCTimerBase* NewTimer(boost::function<void(void)>& func, int64_t millis)
+ RPCTimerBase* NewTimer(std::function<void(void)>& func, int64_t millis)
{
return new QtRPCTimerBase(func, millis);
}
@@ -175,6 +175,10 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &
nDepthInsideSensitive = 1;
filter_begin_pos = chpos;
}
+ // Make sure stack is not empty before adding something
+ if (stack.empty()) {
+ stack.push_back(std::vector<std::string>());
+ }
stack.back().push_back(strArg);
};
@@ -299,6 +303,14 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &
JSONRPCRequest req;
req.params = RPCConvertValues(stack.back()[0], std::vector<std::string>(stack.back().begin() + 1, stack.back().end()));
req.strMethod = stack.back()[0];
+#ifdef ENABLE_WALLET
+ // TODO: Move this logic to WalletModel
+ if (!vpwallets.empty()) {
+ // in Qt, use always the wallet with index 0 when running with multiple wallets
+ QByteArray encodedName = QUrl::toPercentEncoding(QString::fromStdString(vpwallets[0]->GetName()));
+ req.URI = "/wallet/"+std::string(encodedName.constData(), encodedName.length());
+ }
+#endif
lastResult = tableRPC.execute(req);
}
@@ -417,7 +429,11 @@ RPCConsole::RPCConsole(const PlatformStyle *_platformStyle, QWidget *parent) :
consoleFontSize(0)
{
ui->setupUi(this);
- GUIUtil::restoreWindowGeometry("nRPCConsoleWindow", this->size(), this);
+ QSettings settings;
+ if (!restoreGeometry(settings.value("RPCConsoleWindowGeometry").toByteArray())) {
+ // Restore failed (perhaps missing setting), center the window
+ move(QApplication::desktop()->availableGeometry().center() - frameGeometry().center());
+ }
ui->openDebugLogfileButton->setToolTip(ui->openDebugLogfileButton->toolTip().arg(tr(PACKAGE_NAME)));
@@ -455,14 +471,14 @@ RPCConsole::RPCConsole(const PlatformStyle *_platformStyle, QWidget *parent) :
ui->detailWidget->hide();
ui->peerHeading->setText(tr("Select a peer to view detailed information."));
- QSettings settings;
consoleFontSize = settings.value(fontSizeSettingsKey, QFontInfo(QFont()).pointSize()).toInt();
clear();
}
RPCConsole::~RPCConsole()
{
- GUIUtil::saveWindowGeometry("nRPCConsoleWindow", this);
+ QSettings settings;
+ settings.setValue("RPCConsoleWindowGeometry", saveGeometry());
RPCUnsetTimerInterface(rpcTimerInterface);
delete rpcTimerInterface;
delete ui;
@@ -521,7 +537,7 @@ void RPCConsole::setClientModel(ClientModel *model)
setNumConnections(model->getNumConnections());
connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
- setNumBlocks(model->getNumBlocks(), model->getLastBlockDate(), model->getVerificationProgress(NULL), false);
+ setNumBlocks(model->getNumBlocks(), model->getLastBlockDate(), model->getVerificationProgress(nullptr), false);
connect(model, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,double,bool)));
updateNetworkState();
@@ -626,9 +642,12 @@ void RPCConsole::setClientModel(ClientModel *model)
for (size_t i = 0; i < commandList.size(); ++i)
{
wordList << commandList[i].c_str();
+ wordList << ("help " + commandList[i]).c_str();
}
+ wordList.sort();
autoCompleter = new QCompleter(wordList, this);
+ autoCompleter->setModelSorting(QCompleter::CaseSensitivelySortedModel);
ui->lineEdit->setCompleter(autoCompleter);
autoCompleter->popup()->installEventFilter(this);
// Start thread to execute RPC commands.
@@ -667,7 +686,7 @@ void RPCConsole::setFontSize(int newSize)
{
QSettings settings;
- //don't allow a insane font size
+ //don't allow an insane font size
if (newSize < FONT_RANGE.width() || newSize > FONT_RANGE.height())
return;
@@ -723,11 +742,17 @@ void RPCConsole::clear(bool clearHistory)
).arg(fixedFontInfo.family(), QString("%1pt").arg(consoleFontSize))
);
+#ifdef Q_OS_MAC
+ QString clsKey = "(⌘)-L";
+#else
+ QString clsKey = "Ctrl-L";
+#endif
+
message(CMD_REPLY, (tr("Welcome to the %1 RPC console.").arg(tr(PACKAGE_NAME)) + "<br>" +
- tr("Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen.") + "<br>" +
+ tr("Use up and down arrows to navigate history, and %1 to clear screen.").arg("<b>"+clsKey+"</b>") + "<br>" +
tr("Type <b>help</b> for an overview of available commands.")) +
"<br><span class=\"secwarning\">" +
- tr("WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramification of a command.") +
+ tr("WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.") +
"</span>",
true);
}
@@ -822,7 +847,7 @@ void RPCConsole::on_lineEdit_returnPressed()
cmdBeforeBrowsing = QString();
- message(CMD_REQUEST, cmd);
+ message(CMD_REQUEST, QString::fromStdString(strFilteredCmd));
Q_EMIT cmdRequest(cmd);
cmd = QString::fromStdString(strFilteredCmd);
@@ -962,7 +987,7 @@ void RPCConsole::peerLayoutChanged()
if (!clientModel || !clientModel->getPeerTableModel())
return;
- const CNodeCombinedStats *stats = NULL;
+ const CNodeCombinedStats *stats = nullptr;
bool fUnselect = false;
bool fReselect = false;
@@ -1023,11 +1048,11 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats)
peerAddrDetails += "<br />" + tr("via %1").arg(QString::fromStdString(stats->nodeStats.addrLocal));
ui->peerHeading->setText(peerAddrDetails);
ui->peerServices->setText(GUIUtil::formatServicesStr(stats->nodeStats.nServices));
- ui->peerLastSend->setText(stats->nodeStats.nLastSend ? GUIUtil::formatDurationStr(GetTime() - stats->nodeStats.nLastSend) : tr("never"));
- ui->peerLastRecv->setText(stats->nodeStats.nLastRecv ? GUIUtil::formatDurationStr(GetTime() - stats->nodeStats.nLastRecv) : tr("never"));
+ ui->peerLastSend->setText(stats->nodeStats.nLastSend ? GUIUtil::formatDurationStr(GetSystemTimeInSeconds() - stats->nodeStats.nLastSend) : tr("never"));
+ ui->peerLastRecv->setText(stats->nodeStats.nLastRecv ? GUIUtil::formatDurationStr(GetSystemTimeInSeconds() - stats->nodeStats.nLastRecv) : tr("never"));
ui->peerBytesSent->setText(FormatBytes(stats->nodeStats.nSendBytes));
ui->peerBytesRecv->setText(FormatBytes(stats->nodeStats.nRecvBytes));
- ui->peerConnTime->setText(GUIUtil::formatDurationStr(GetTime() - stats->nodeStats.nTimeConnected));
+ ui->peerConnTime->setText(GUIUtil::formatDurationStr(GetSystemTimeInSeconds() - stats->nodeStats.nTimeConnected));
ui->peerPingTime->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingTime));
ui->peerPingWait->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingWait));
ui->peerMinPing->setText(GUIUtil::formatPingTime(stats->nodeStats.dMinPing));
@@ -1111,7 +1136,7 @@ void RPCConsole::disconnectSelectedNode()
for(int i = 0; i < nodes.count(); i++)
{
// Get currently selected peer address
- NodeId id = nodes.at(i).data().toInt();
+ NodeId id = nodes.at(i).data().toLongLong();
// Find the node, disconnect it and clear the selected node
if(g_connman->DisconnectNode(id))
clearSelectedNode();
@@ -1128,7 +1153,7 @@ void RPCConsole::banSelectedNode(int bantime)
for(int i = 0; i < nodes.count(); i++)
{
// Get currently selected peer address
- NodeId id = nodes.at(i).data().toInt();
+ NodeId id = nodes.at(i).data().toLongLong();
// Get currently selected peer address
int detailNodeRow = clientModel->getPeerTableModel()->getRowByNodeId(id);
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index ec531c99c8..da06818f87 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -36,8 +36,8 @@ public:
explicit RPCConsole(const PlatformStyle *platformStyle, QWidget *parent);
~RPCConsole();
- static bool RPCParseCommandLine(std::string &strResult, const std::string &strCommand, bool fExecute, std::string * const pstrFilteredOut = NULL);
- static bool RPCExecuteCommandLine(std::string &strResult, const std::string &strCommand, std::string * const pstrFilteredOut = NULL) {
+ static bool RPCParseCommandLine(std::string &strResult, const std::string &strCommand, bool fExecute, std::string * const pstrFilteredOut = nullptr);
+ static bool RPCExecuteCommandLine(std::string &strResult, const std::string &strCommand, std::string * const pstrFilteredOut = nullptr) {
return RPCParseCommandLine(strResult, strCommand, true, pstrFilteredOut);
}
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 5aeda7a30d..6309070fef 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -16,19 +16,39 @@
#include "walletmodel.h"
#include "base58.h"
+#include "chainparams.h"
#include "wallet/coincontrol.h"
#include "validation.h" // mempool and minRelayTxFee
#include "ui_interface.h"
#include "txmempool.h"
-#include "wallet/wallet.h"
+#include "policy/fees.h"
+#include "wallet/fees.h"
+#include <QFontMetrics>
#include <QMessageBox>
#include <QScrollBar>
#include <QSettings>
#include <QTextDocument>
#include <QTimer>
-#define SEND_CONFIRM_DELAY 3
+static const std::array<int, 9> confTargets = { {2, 4, 6, 12, 24, 48, 144, 504, 1008} };
+int getConfTargetForIndex(int index) {
+ if (index+1 > static_cast<int>(confTargets.size())) {
+ return confTargets.back();
+ }
+ if (index < 0) {
+ return confTargets[0];
+ }
+ return confTargets[index];
+}
+int getIndexForConfTarget(int target) {
+ for (unsigned int i = 0; i < confTargets.size(); i++) {
+ if (confTargets[i] >= target) {
+ return i;
+ }
+ }
+ return confTargets.size() - 1;
+}
SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
QDialog(parent),
@@ -94,10 +114,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *p
settings.setValue("nFeeRadio", 1); // custom
if (!settings.contains("nFeeRadio"))
settings.setValue("nFeeRadio", 0); // recommended
- if (!settings.contains("nCustomFeeRadio") && settings.contains("nTransactionFee") && settings.value("nTransactionFee").toLongLong() > 0) // compatibility
- settings.setValue("nCustomFeeRadio", 1); // total at least
- if (!settings.contains("nCustomFeeRadio"))
- settings.setValue("nCustomFeeRadio", 0); // per kilobyte
if (!settings.contains("nSmartFeeSliderPosition"))
settings.setValue("nSmartFeeSliderPosition", 0);
if (!settings.contains("nTransactionFee"))
@@ -107,9 +123,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *p
ui->groupFee->setId(ui->radioSmartFee, 0);
ui->groupFee->setId(ui->radioCustomFee, 1);
ui->groupFee->button((int)std::max(0, std::min(1, settings.value("nFeeRadio").toInt())))->setChecked(true);
- ui->groupCustomFee->setId(ui->radioCustomPerKilobyte, 0);
- ui->groupCustomFee->setId(ui->radioCustomAtLeast, 1);
- ui->groupCustomFee->button((int)std::max(0, std::min(1, settings.value("nCustomFeeRadio").toInt())))->setChecked(true);
ui->customFee->setValue(settings.value("nTransactionFee").toLongLong());
ui->checkBoxMinimumFee->setChecked(settings.value("fPayOnlyMinFee").toBool());
minimizeFeeSection(settings.value("fFeeSectionMinimized").toBool());
@@ -152,32 +165,40 @@ void SendCoinsDialog::setModel(WalletModel *_model)
coinControlUpdateLabels();
// fee section
- connect(ui->sliderSmartFee, SIGNAL(valueChanged(int)), this, SLOT(updateSmartFeeLabel()));
- connect(ui->sliderSmartFee, SIGNAL(valueChanged(int)), this, SLOT(updateGlobalFeeVariables()));
- connect(ui->sliderSmartFee, SIGNAL(valueChanged(int)), this, SLOT(coinControlUpdateLabels()));
+ for (const int &n : confTargets) {
+ ui->confTargetSelector->addItem(tr("%1 (%2 blocks)").arg(GUIUtil::formatNiceTimeOffset(n*Params().GetConsensus().nPowTargetSpacing)).arg(n));
+ }
+ connect(ui->confTargetSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(updateSmartFeeLabel()));
+ connect(ui->confTargetSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(coinControlUpdateLabels()));
connect(ui->groupFee, SIGNAL(buttonClicked(int)), this, SLOT(updateFeeSectionControls()));
- connect(ui->groupFee, SIGNAL(buttonClicked(int)), this, SLOT(updateGlobalFeeVariables()));
connect(ui->groupFee, SIGNAL(buttonClicked(int)), this, SLOT(coinControlUpdateLabels()));
- connect(ui->groupCustomFee, SIGNAL(buttonClicked(int)), this, SLOT(updateGlobalFeeVariables()));
- connect(ui->groupCustomFee, SIGNAL(buttonClicked(int)), this, SLOT(coinControlUpdateLabels()));
- connect(ui->customFee, SIGNAL(valueChanged()), this, SLOT(updateGlobalFeeVariables()));
connect(ui->customFee, SIGNAL(valueChanged()), this, SLOT(coinControlUpdateLabels()));
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(setMinimumFee()));
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateFeeSectionControls()));
- connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateGlobalFeeVariables()));
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
- ui->customFee->setSingleStep(CWallet::GetRequiredFee(1000));
+ connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(updateSmartFeeLabel()));
+ connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
+ ui->customFee->setSingleStep(GetRequiredFee(1000));
updateFeeSectionControls();
updateMinFeeLabel();
updateSmartFeeLabel();
- updateGlobalFeeVariables();
+
+ // set default rbf checkbox state
+ ui->optInRBF->setCheckState(model->getDefaultWalletRbf() ? Qt::Checked : Qt::Unchecked);
// set the smartfee-sliders default value (wallets default conf.target or last stored value)
QSettings settings;
- if (settings.value("nSmartFeeSliderPosition").toInt() == 0)
- ui->sliderSmartFee->setValue(ui->sliderSmartFee->maximum() - model->getDefaultConfirmTarget() + 2);
+ if (settings.value("nSmartFeeSliderPosition").toInt() != 0) {
+ // migrate nSmartFeeSliderPosition to nConfTarget
+ // nConfTarget is available since 0.15 (replaced nSmartFeeSliderPosition)
+ int nConfirmTarget = 25 - settings.value("nSmartFeeSliderPosition").toInt(); // 25 == old slider range
+ settings.setValue("nConfTarget", nConfirmTarget);
+ settings.remove("nSmartFeeSliderPosition");
+ }
+ if (settings.value("nConfTarget").toInt() == 0)
+ ui->confTargetSelector->setCurrentIndex(getIndexForConfTarget(model->getDefaultConfirmTarget()));
else
- ui->sliderSmartFee->setValue(settings.value("nSmartFeeSliderPosition").toInt());
+ ui->confTargetSelector->setCurrentIndex(getIndexForConfTarget(settings.value("nConfTarget").toInt()));
}
}
@@ -186,8 +207,7 @@ SendCoinsDialog::~SendCoinsDialog()
QSettings settings;
settings.setValue("fFeeSectionMinimized", fFeeMinimized);
settings.setValue("nFeeRadio", ui->groupFee->checkedId());
- settings.setValue("nCustomFeeRadio", ui->groupCustomFee->checkedId());
- settings.setValue("nSmartFeeSliderPosition", ui->sliderSmartFee->value());
+ settings.setValue("nConfTarget", getConfTargetForIndex(ui->confTargetSelector->currentIndex()));
settings.setValue("nTransactionFee", (qint64)ui->customFee->value());
settings.setValue("fPayOnlyMinFee", ui->checkBoxMinimumFee->isChecked());
@@ -240,12 +260,10 @@ void SendCoinsDialog::on_sendButton_clicked()
CCoinControl ctrl;
if (model->getOptionsModel()->getCoinControlFeatures())
ctrl = *CoinControlDialog::coinControl;
- if (ui->radioSmartFee->isChecked())
- ctrl.nConfirmTarget = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;
- else
- ctrl.nConfirmTarget = 0;
- prepareStatus = model->prepareTransaction(currentTransaction, &ctrl);
+ updateCoinControlState(ctrl);
+
+ prepareStatus = model->prepareTransaction(currentTransaction, ctrl);
// process prepareStatus and on error generate message shown to user
processSendCoinsReturn(prepareStatus,
@@ -260,7 +278,7 @@ void SendCoinsDialog::on_sendButton_clicked()
// Format confirmation message
QStringList formatted;
- Q_FOREACH(const SendCoinsRecipient &rcp, currentTransaction.getRecipients())
+ for (const SendCoinsRecipient &rcp : currentTransaction.getRecipients())
{
// generate bold amount string
QString amount = "<b>" + BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount);
@@ -314,7 +332,7 @@ void SendCoinsDialog::on_sendButton_clicked()
questionString.append("<hr />");
CAmount totalAmount = currentTransaction.getTotalTransactionAmount() + txFee;
QStringList alternativeUnits;
- Q_FOREACH(BitcoinUnits::Unit u, BitcoinUnits::availableUnits())
+ for (BitcoinUnits::Unit u : BitcoinUnits::availableUnits())
{
if(u != model->getOptionsModel()->getDisplayUnit())
alternativeUnits.append(BitcoinUnits::formatHtmlWithUnit(u, totalAmount));
@@ -324,6 +342,13 @@ void SendCoinsDialog::on_sendButton_clicked()
questionString.append(QString("<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span>")
.arg(alternativeUnits.join(" " + tr("or") + "<br />")));
+ if (ui->optInRBF->isChecked())
+ {
+ questionString.append("<hr /><span>");
+ questionString.append(tr("This transaction signals replaceability (optin-RBF)."));
+ questionString.append("</span>");
+ }
+
SendConfirmationDialog confirmationDialog(tr("Confirm send coins"),
questionString.arg(formatted.join("<br />")), SEND_CONFIRM_DELAY, this);
confirmationDialog.exec();
@@ -576,50 +601,22 @@ void SendCoinsDialog::on_buttonMinimizeFee_clicked()
void SendCoinsDialog::setMinimumFee()
{
- ui->radioCustomPerKilobyte->setChecked(true);
- ui->customFee->setValue(CWallet::GetRequiredFee(1000));
+ ui->customFee->setValue(GetRequiredFee(1000));
}
void SendCoinsDialog::updateFeeSectionControls()
{
- ui->sliderSmartFee ->setEnabled(ui->radioSmartFee->isChecked());
+ ui->confTargetSelector ->setEnabled(ui->radioSmartFee->isChecked());
ui->labelSmartFee ->setEnabled(ui->radioSmartFee->isChecked());
ui->labelSmartFee2 ->setEnabled(ui->radioSmartFee->isChecked());
ui->labelSmartFee3 ->setEnabled(ui->radioSmartFee->isChecked());
ui->labelFeeEstimation ->setEnabled(ui->radioSmartFee->isChecked());
- ui->labelSmartFeeNormal ->setEnabled(ui->radioSmartFee->isChecked());
- ui->labelSmartFeeFast ->setEnabled(ui->radioSmartFee->isChecked());
- ui->confirmationTargetLabel ->setEnabled(ui->radioSmartFee->isChecked());
ui->checkBoxMinimumFee ->setEnabled(ui->radioCustomFee->isChecked());
ui->labelMinFeeWarning ->setEnabled(ui->radioCustomFee->isChecked());
- ui->radioCustomPerKilobyte ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked());
- ui->radioCustomAtLeast ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked() && CoinControlDialog::coinControl->HasSelected());
+ ui->labelCustomPerKilobyte ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked());
ui->customFee ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked());
}
-void SendCoinsDialog::updateGlobalFeeVariables()
-{
- if (ui->radioSmartFee->isChecked())
- {
- int nConfirmTarget = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;
- payTxFee = CFeeRate(0);
-
- // set nMinimumTotalFee to 0 to not accidentally pay a custom fee
- CoinControlDialog::coinControl->nMinimumTotalFee = 0;
-
- // show the estimated reuquired time for confirmation
- ui->confirmationTargetLabel->setText(GUIUtil::formatDurationStr(nConfirmTarget*600)+" / "+tr("%n block(s)", "", nConfirmTarget));
- }
- else
- {
- payTxFee = CFeeRate(ui->customFee->value());
-
- // if user has selected to set a minimum absolute fee, pass the value to coincontrol
- // set nMinimumTotalFee to 0 in case of user has selected that the fee is per KB
- CoinControlDialog::coinControl->nMinimumTotalFee = ui->radioCustomAtLeast->isChecked() ? ui->customFee->value() : 0;
- }
-}
-
void SendCoinsDialog::updateFeeMinimizedLabel()
{
if(!model || !model->getOptionsModel())
@@ -628,8 +625,7 @@ void SendCoinsDialog::updateFeeMinimizedLabel()
if (ui->radioSmartFee->isChecked())
ui->labelFeeMinimized->setText(ui->labelSmartFee->text());
else {
- ui->labelFeeMinimized->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), ui->customFee->value()) +
- ((ui->radioCustomPerKilobyte->isChecked()) ? "/kB" : ""));
+ ui->labelFeeMinimized->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), ui->customFee->value()) + "/kB");
}
}
@@ -637,31 +633,49 @@ void SendCoinsDialog::updateMinFeeLabel()
{
if (model && model->getOptionsModel())
ui->checkBoxMinimumFee->setText(tr("Pay only the required fee of %1").arg(
- BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), CWallet::GetRequiredFee(1000)) + "/kB")
+ BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), GetRequiredFee(1000)) + "/kB")
);
}
+void SendCoinsDialog::updateCoinControlState(CCoinControl& ctrl)
+{
+ if (ui->radioCustomFee->isChecked()) {
+ ctrl.m_feerate = CFeeRate(ui->customFee->value());
+ } else {
+ ctrl.m_feerate.reset();
+ }
+ // Avoid using global defaults when sending money from the GUI
+ // Either custom fee will be used or if not selected, the confirmation target from dropdown box
+ ctrl.m_confirm_target = getConfTargetForIndex(ui->confTargetSelector->currentIndex());
+ ctrl.signalRbf = ui->optInRBF->isChecked();
+}
+
void SendCoinsDialog::updateSmartFeeLabel()
{
if(!model || !model->getOptionsModel())
return;
+ CCoinControl coin_control;
+ updateCoinControlState(coin_control);
+ coin_control.m_feerate.reset(); // Explicitly use only fee estimation rate for smart fee labels
+ FeeCalculation feeCalc;
+ CFeeRate feeRate = CFeeRate(GetMinimumFee(1000, coin_control, ::mempool, ::feeEstimator, &feeCalc));
- int nBlocksToConfirm = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2;
- int estimateFoundAtBlocks = nBlocksToConfirm;
- CFeeRate feeRate = mempool.estimateSmartFee(nBlocksToConfirm, &estimateFoundAtBlocks);
- if (feeRate <= CFeeRate(0)) // not enough data => minfee
- {
- ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(),
- std::max(CWallet::fallbackFee.GetFeePerK(), CWallet::GetRequiredFee(1000))) + "/kB");
+ ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), feeRate.GetFeePerK()) + "/kB");
+
+ if (feeCalc.reason == FeeReason::FALLBACK) {
ui->labelSmartFee2->show(); // (Smart fee not initialized yet. This usually takes a few blocks...)
ui->labelFeeEstimation->setText("");
+ ui->fallbackFeeWarningLabel->setVisible(true);
+ int lightness = ui->fallbackFeeWarningLabel->palette().color(QPalette::WindowText).lightness();
+ QColor warning_colour(255 - (lightness / 5), 176 - (lightness / 3), 48 - (lightness / 14));
+ ui->fallbackFeeWarningLabel->setStyleSheet("QLabel { color: " + warning_colour.name() + "; }");
+ ui->fallbackFeeWarningLabel->setIndent(QFontMetrics(ui->fallbackFeeWarningLabel->font()).width("x"));
}
else
{
- ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(),
- std::max(feeRate.GetFeePerK(), CWallet::GetRequiredFee(1000))) + "/kB");
ui->labelSmartFee2->hide();
- ui->labelFeeEstimation->setText(tr("Estimated to begin confirmation within %n block(s).", "", estimateFoundAtBlocks));
+ ui->labelFeeEstimation->setText(tr("Estimated to begin confirmation within %n block(s).", "", feeCalc.returnedTarget));
+ ui->fallbackFeeWarningLabel->setVisible(false);
}
updateFeeMinimizedLabel();
@@ -717,8 +731,6 @@ void SendCoinsDialog::coinControlFeatureChanged(bool checked)
if (!checked && model) // coin control features disabled
CoinControlDialog::coinControl->SetNull();
- // make sure we set back the confirmation target
- updateGlobalFeeVariables();
coinControlUpdateLabels();
}
@@ -755,22 +767,19 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text)
CoinControlDialog::coinControl->destChange = CNoDestination();
ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:red;}");
- CBitcoinAddress addr = CBitcoinAddress(text.toStdString());
+ const CTxDestination dest = DecodeDestination(text.toStdString());
if (text.isEmpty()) // Nothing entered
{
ui->labelCoinControlChangeLabel->setText("");
}
- else if (!addr.IsValid()) // Invalid address
+ else if (!IsValidDestination(dest)) // Invalid address
{
ui->labelCoinControlChangeLabel->setText(tr("Warning: Invalid Bitcoin address"));
}
else // Valid address
{
- CKeyID keyid;
- addr.GetKeyID(keyid);
- if (!model->havePrivKey(keyid)) // Unknown change address
- {
+ if (!model->IsSpendable(dest)) {
ui->labelCoinControlChangeLabel->setText(tr("Warning: Unknown change address"));
// confirmation dialog
@@ -778,7 +787,7 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text)
QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);
if(btnRetVal == QMessageBox::Yes)
- CoinControlDialog::coinControl->destChange = addr.Get();
+ CoinControlDialog::coinControl->destChange = dest;
else
{
ui->lineEditCoinControlChange->setText("");
@@ -797,7 +806,7 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text)
else
ui->labelCoinControlChangeLabel->setText(tr("(no label)"));
- CoinControlDialog::coinControl->destChange = addr.Get();
+ CoinControlDialog::coinControl->destChange = dest;
}
}
}
@@ -809,24 +818,12 @@ void SendCoinsDialog::coinControlUpdateLabels()
if (!model || !model->getOptionsModel())
return;
- if (model->getOptionsModel()->getCoinControlFeatures())
- {
- // enable minimum absolute fee UI controls
- ui->radioCustomAtLeast->setVisible(true);
-
- // only enable the feature if inputs are selected
- ui->radioCustomAtLeast->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked() &&CoinControlDialog::coinControl->HasSelected());
- }
- else
- {
- // in case coin control is disabled (=default), hide minimum absolute fee UI controls
- ui->radioCustomAtLeast->setVisible(false);
- return;
- }
+ updateCoinControlState(*CoinControlDialog::coinControl);
// set pay amounts
CoinControlDialog::payAmounts.clear();
CoinControlDialog::fSubtractFeeFromAmount = false;
+
for(int i = 0; i < ui->entries->count(); ++i)
{
SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index a402edc961..70b4aa5a03 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -13,7 +13,6 @@
#include <QTimer>
class ClientModel;
-class OptionsModel;
class PlatformStyle;
class SendCoinsEntry;
class SendCoinsRecipient;
@@ -69,6 +68,8 @@ private:
void processSendCoinsReturn(const WalletModel::SendCoinsReturn &sendCoinsReturn, const QString &msgArg = QString());
void minimizeFeeSection(bool fMinimize);
void updateFeeMinimizedLabel();
+ // Update the passed in CCoinControl with state from the GUI
+ void updateCoinControlState(CCoinControl& ctrl);
private Q_SLOTS:
void on_sendButton_clicked();
@@ -92,7 +93,6 @@ private Q_SLOTS:
void updateFeeSectionControls();
void updateMinFeeLabel();
void updateSmartFeeLabel();
- void updateGlobalFeeVariables();
Q_SIGNALS:
// Fired when a message should be reported to the user
@@ -100,13 +100,14 @@ Q_SIGNALS:
};
+#define SEND_CONFIRM_DELAY 3
class SendConfirmationDialog : public QMessageBox
{
Q_OBJECT
public:
- SendConfirmationDialog(const QString &title, const QString &text, int secDelay = 0, QWidget *parent = 0);
+ SendConfirmationDialog(const QString &title, const QString &text, int secDelay = SEND_CONFIRM_DELAY, QWidget *parent = 0);
int exec();
private Q_SLOTS:
diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp
index 0950ed0234..cba9d4da38 100644
--- a/src/qt/signverifymessagedialog.cpp
+++ b/src/qt/signverifymessagedialog.cpp
@@ -117,16 +117,14 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
/* Clear old signature to ensure users don't get confused on error with an old signature displayed */
ui->signatureOut_SM->clear();
- CBitcoinAddress addr(ui->addressIn_SM->text().toStdString());
- if (!addr.IsValid())
- {
+ CTxDestination destination = DecodeDestination(ui->addressIn_SM->text().toStdString());
+ if (!IsValidDestination(destination)) {
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_SM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again."));
return;
}
- CKeyID keyID;
- if (!addr.GetKeyID(keyID))
- {
+ const CKeyID* keyID = boost::get<CKeyID>(&destination);
+ if (!keyID) {
ui->addressIn_SM->setValid(false);
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_SM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again."));
@@ -142,7 +140,7 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
}
CKey key;
- if (!model->getPrivKey(keyID, key))
+ if (!model->getPrivKey(*keyID, key))
{
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_SM->setText(tr("Private key for the entered address is not available."));
@@ -164,7 +162,7 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
ui->statusLabel_SM->setStyleSheet("QLabel { color: green; }");
ui->statusLabel_SM->setText(QString("<nobr>") + tr("Message signed.") + QString("</nobr>"));
- ui->signatureOut_SM->setText(QString::fromStdString(EncodeBase64(&vchSig[0], vchSig.size())));
+ ui->signatureOut_SM->setText(QString::fromStdString(EncodeBase64(vchSig.data(), vchSig.size())));
}
void SignVerifyMessageDialog::on_copySignatureButton_SM_clicked()
@@ -197,16 +195,13 @@ void SignVerifyMessageDialog::on_addressBookButton_VM_clicked()
void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()
{
- CBitcoinAddress addr(ui->addressIn_VM->text().toStdString());
- if (!addr.IsValid())
- {
+ CTxDestination destination = DecodeDestination(ui->addressIn_VM->text().toStdString());
+ if (!IsValidDestination(destination)) {
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_VM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again."));
return;
}
- CKeyID keyID;
- if (!addr.GetKeyID(keyID))
- {
+ if (!boost::get<CKeyID>(&destination)) {
ui->addressIn_VM->setValid(false);
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_VM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again."));
@@ -237,8 +232,7 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()
return;
}
- if (!(CBitcoinAddress(pubkey.GetID()) == addr))
- {
+ if (!(CTxDestination(pubkey.GetID()) == destination)) {
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_VM->setText(QString("<nobr>") + tr("Message verification failed.") + QString("</nobr>"));
return;
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index f4377247e1..a1fbba963c 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -131,6 +131,7 @@ SplashScreen::SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle)
move(QApplication::desktop()->screenGeometry().center() - r.center());
subscribeToCoreSignals();
+ installEventFilter(this);
}
SplashScreen::~SplashScreen()
@@ -138,6 +139,16 @@ SplashScreen::~SplashScreen()
unsubscribeFromCoreSignals();
}
+bool SplashScreen::eventFilter(QObject * obj, QEvent * ev) {
+ if (ev->type() == QEvent::KeyPress) {
+ QKeyEvent *keyEvent = static_cast<QKeyEvent *>(ev);
+ if(keyEvent->text()[0] == 'q') {
+ StartShutdown();
+ }
+ }
+ return QObject::eventFilter(obj, ev);
+}
+
void SplashScreen::slotFinish(QWidget *mainWin)
{
Q_UNUSED(mainWin);
@@ -159,15 +170,18 @@ static void InitMessage(SplashScreen *splash, const std::string &message)
Q_ARG(QColor, QColor(55,55,55)));
}
-static void ShowProgress(SplashScreen *splash, const std::string &title, int nProgress)
+static void ShowProgress(SplashScreen *splash, const std::string &title, int nProgress, bool resume_possible)
{
- InitMessage(splash, title + strprintf("%d", nProgress) + "%");
+ InitMessage(splash, title + std::string("\n") +
+ (resume_possible ? _("(press q to shutdown and continue later)")
+ : _("press q to shutdown")) +
+ strprintf("\n%d", nProgress) + "%");
}
#ifdef ENABLE_WALLET
void SplashScreen::ConnectWallet(CWallet* wallet)
{
- wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
+ wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2, false));
connectedWallets.push_back(wallet);
}
#endif
@@ -176,7 +190,7 @@ void SplashScreen::subscribeToCoreSignals()
{
// Connect signals to client
uiInterface.InitMessage.connect(boost::bind(InitMessage, this, _1));
- uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
+ uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2, _3));
#ifdef ENABLE_WALLET
uiInterface.LoadWallet.connect(boost::bind(&SplashScreen::ConnectWallet, this, _1));
#endif
@@ -186,10 +200,10 @@ void SplashScreen::unsubscribeFromCoreSignals()
{
// Disconnect signals from client
uiInterface.InitMessage.disconnect(boost::bind(InitMessage, this, _1));
- uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
+ uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2, _3));
#ifdef ENABLE_WALLET
- Q_FOREACH(CWallet* const & pwallet, connectedWallets) {
- pwallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
+ for (CWallet* const & pwallet : connectedWallets) {
+ pwallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2, false));
}
#endif
}
diff --git a/src/qt/splashscreen.h b/src/qt/splashscreen.h
index 95a65cc53c..c6cfd503f7 100644
--- a/src/qt/splashscreen.h
+++ b/src/qt/splashscreen.h
@@ -5,6 +5,7 @@
#ifndef BITCOIN_QT_SPLASHSCREEN_H
#define BITCOIN_QT_SPLASHSCREEN_H
+#include <functional>
#include <QSplashScreen>
class CWallet;
@@ -35,6 +36,9 @@ public Q_SLOTS:
/** Show message and progress */
void showMessage(const QString &message, int alignment, const QColor &color);
+protected:
+ bool eventFilter(QObject * obj, QEvent * ev);
+
private:
/** Connect core signals to splash screen */
void subscribeToCoreSignals();
diff --git a/src/qt/test/paymentservertests.cpp b/src/qt/test/paymentservertests.cpp
index 84ccfea730..273bd10487 100644
--- a/src/qt/test/paymentservertests.cpp
+++ b/src/qt/test/paymentservertests.cpp
@@ -24,8 +24,8 @@ X509 *parse_b64der_cert(const char* cert_data)
{
std::vector<unsigned char> data = DecodeBase64(cert_data);
assert(data.size() > 0);
- const unsigned char* dptr = &data[0];
- X509 *cert = d2i_X509(NULL, &dptr, data.size());
+ const unsigned char* dptr = data.data();
+ X509 *cert = d2i_X509(nullptr, &dptr, data.size());
assert(cert);
return cert;
}
@@ -43,7 +43,7 @@ static SendCoinsRecipient handleRequest(PaymentServer* server, std::vector<unsig
// Write data to a temp file:
QTemporaryFile f;
f.open();
- f.write((const char*)&data[0], data.size());
+ f.write((const char*)data.data(), data.size());
f.close();
// Create a QObject, install event filter from PaymentServer
@@ -66,7 +66,7 @@ void PaymentServerTests::paymentServerTests()
{
SelectParams(CBaseChainParams::MAIN);
OptionsModel optionsModel;
- PaymentServer* server = new PaymentServer(NULL, false);
+ PaymentServer* server = new PaymentServer(nullptr, false);
X509_STORE* caStore = X509_STORE_new();
X509_STORE_add_cert(caStore, parse_b64der_cert(caCert1_BASE64));
PaymentServer::LoadRootCAs(caStore);
@@ -139,16 +139,16 @@ void PaymentServerTests::paymentServerTests()
// Contains a testnet paytoaddress, so payment request network doesn't match client network:
data = DecodeBase64(paymentrequest1_cert2_BASE64);
- byteArray = QByteArray((const char*)&data[0], data.size());
+ byteArray = QByteArray((const char*)data.data(), data.size());
r.paymentRequest.parse(byteArray);
// Ensure the request is initialized, because network "main" is default, even for
- // uninizialized payment requests and that will fail our test here.
+ // uninitialized payment requests and that will fail our test here.
QVERIFY(r.paymentRequest.IsInitialized());
QCOMPARE(PaymentServer::verifyNetwork(r.paymentRequest.getDetails()), false);
// Expired payment request (expires is set to 1 = 1970-01-01 00:00:01):
data = DecodeBase64(paymentrequest2_cert2_BASE64);
- byteArray = QByteArray((const char*)&data[0], data.size());
+ byteArray = QByteArray((const char*)data.data(), data.size());
r.paymentRequest.parse(byteArray);
// Ensure the request is initialized
QVERIFY(r.paymentRequest.IsInitialized());
@@ -159,7 +159,7 @@ void PaymentServerTests::paymentServerTests()
// 9223372036854775807 (uint64), 9223372036854775807 (int64_t) and -1 (int32_t)
// -1 is 1969-12-31 23:59:59 (for a 32 bit time values)
data = DecodeBase64(paymentrequest3_cert2_BASE64);
- byteArray = QByteArray((const char*)&data[0], data.size());
+ byteArray = QByteArray((const char*)data.data(), data.size());
r.paymentRequest.parse(byteArray);
// Ensure the request is initialized
QVERIFY(r.paymentRequest.IsInitialized());
@@ -170,7 +170,7 @@ void PaymentServerTests::paymentServerTests()
// 9223372036854775808 (uint64), -9223372036854775808 (int64_t) and 0 (int32_t)
// 0 is 1970-01-01 00:00:00 (for a 32 bit time values)
data = DecodeBase64(paymentrequest4_cert2_BASE64);
- byteArray = QByteArray((const char*)&data[0], data.size());
+ byteArray = QByteArray((const char*)data.data(), data.size());
r.paymentRequest.parse(byteArray);
// Ensure the request is initialized
QVERIFY(r.paymentRequest.IsInitialized());
@@ -190,13 +190,13 @@ void PaymentServerTests::paymentServerTests()
// Payment request with amount overflow (amount is set to 21000001 BTC):
data = DecodeBase64(paymentrequest5_cert2_BASE64);
- byteArray = QByteArray((const char*)&data[0], data.size());
+ byteArray = QByteArray((const char*)data.data(), data.size());
r.paymentRequest.parse(byteArray);
// Ensure the request is initialized
QVERIFY(r.paymentRequest.IsInitialized());
// Extract address and amount from the request
QList<std::pair<CScript, CAmount> > sendingTos = r.paymentRequest.getPayTo();
- Q_FOREACH (const PAIRTYPE(CScript, CAmount)& sendingTo, sendingTos) {
+ for (const std::pair<CScript, CAmount>& sendingTo : sendingTos) {
CTxDestination dest;
if (ExtractDestination(sendingTo.first, dest))
QCOMPARE(PaymentServer::verifyAmount(sendingTo.second), false);
@@ -205,7 +205,7 @@ void PaymentServerTests::paymentServerTests()
delete server;
}
-void RecipientCatcher::getRecipient(SendCoinsRecipient r)
+void RecipientCatcher::getRecipient(const SendCoinsRecipient& r)
{
recipient = r;
}
diff --git a/src/qt/test/paymentservertests.h b/src/qt/test/paymentservertests.h
index 9ffcbb02ac..faf167f2c6 100644
--- a/src/qt/test/paymentservertests.h
+++ b/src/qt/test/paymentservertests.h
@@ -26,7 +26,7 @@ class RecipientCatcher : public QObject
Q_OBJECT
public Q_SLOTS:
- void getRecipient(SendCoinsRecipient r);
+ void getRecipient(const SendCoinsRecipient& r);
public:
SendCoinsRecipient recipient;
diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp
index fbec5722b6..70fdd4bf58 100644
--- a/src/qt/test/rpcnestedtests.cpp
+++ b/src/qt/test/rpcnestedtests.cpp
@@ -6,19 +6,18 @@
#include "chainparams.h"
#include "consensus/validation.h"
+#include "fs.h"
#include "validation.h"
#include "rpc/register.h"
#include "rpc/server.h"
#include "rpcconsole.h"
-#include "test/testutil.h"
+#include "test/test_bitcoin.h"
#include "univalue.h"
#include "util.h"
#include <QDir>
#include <QtGlobal>
-#include <boost/filesystem.hpp>
-
static UniValue rpcNestedTest_rpc(const JSONRPCRequest& request)
{
if (request.fHelp) {
@@ -29,33 +28,17 @@ static UniValue rpcNestedTest_rpc(const JSONRPCRequest& request)
static const CRPCCommand vRPCCommands[] =
{
- { "test", "rpcNestedTest", &rpcNestedTest_rpc, true },
+ { "test", "rpcNestedTest", &rpcNestedTest_rpc, {} },
};
void RPCNestedTests::rpcNestedTests()
{
- UniValue jsonRPCError;
-
// do some test setup
// could be moved to a more generic place when we add more tests on QT level
- const CChainParams& chainparams = Params();
- RegisterAllCoreRPCCommands(tableRPC);
tableRPC.appendCommand("rpcNestedTest", &vRPCCommands[0]);
- ClearDatadirCache();
- std::string path = QDir::tempPath().toStdString() + "/" + strprintf("test_bitcoin_qt_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000)));
- QDir dir(QString::fromStdString(path));
- dir.mkpath(".");
- ForceSetArg("-datadir", path);
//mempool.setSanityCheck(1.0);
- pblocktree = new CBlockTreeDB(1 << 20, true);
- pcoinsdbview = new CCoinsViewDB(1 << 23, true);
- pcoinsTip = new CCoinsViewCache(pcoinsdbview);
- InitBlockIndex(chainparams);
- {
- CValidationState state;
- bool ok = ActivateBestChain(state, chainparams);
- QVERIFY(ok);
- }
+
+ TestingSetup test;
SetRPCWarmupFinished();
@@ -80,13 +63,13 @@ void RPCNestedTests::rpcNestedTests()
RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo "); //whitespace at the end will be tolerated
QVERIFY(result.substr(0,1) == "{");
- (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()[\"chain\"]")); //Quote path identifier are allowed, but look after a child contaning the quotes in the key
+ (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()[\"chain\"]")); //Quote path identifier are allowed, but look after a child containing the quotes in the key
QVERIFY(result == "null");
(RPCConsole::RPCExecuteCommandLine(result, "createrawtransaction [] {} 0")); //parameter not in brackets are allowed
(RPCConsole::RPCExecuteCommandLine(result2, "createrawtransaction([],{},0)")); //parameter in brackets are allowed
QVERIFY(result == result2);
- (RPCConsole::RPCExecuteCommandLine(result2, "createrawtransaction( [], {} , 0 )")); //whitespace between parametres is allowed
+ (RPCConsole::RPCExecuteCommandLine(result2, "createrawtransaction( [], {} , 0 )")); //whitespace between parameters is allowed
QVERIFY(result == result2);
RPCConsole::RPCExecuteCommandLine(result, "getblock(getbestblockhash())[tx][0]", &filtered);
@@ -147,10 +130,4 @@ void RPCNestedTests::rpcNestedTests()
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,abc)"), std::runtime_error); //don't tollerate empty arguments when using ,
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tollerate empty arguments when using ,
#endif
-
- delete pcoinsTip;
- delete pcoinsdbview;
- delete pblocktree;
-
- boost::filesystem::remove_all(boost::filesystem::path(path));
}
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index d44d711315..4c04e67ccc 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -7,7 +7,6 @@
#endif
#include "chainparams.h"
-#include "key.h"
#include "rpcnestedtests.h"
#include "util.h"
#include "uritests.h"
@@ -15,20 +14,34 @@
#ifdef ENABLE_WALLET
#include "paymentservertests.h"
+#include "wallettests.h"
#endif
-#include <QCoreApplication>
+#include <QApplication>
#include <QObject>
#include <QTest>
#include <openssl/ssl.h>
-#if defined(QT_STATICPLUGIN) && QT_VERSION < 0x050000
+#if defined(QT_STATICPLUGIN)
#include <QtPlugin>
+#if QT_VERSION < 0x050000
Q_IMPORT_PLUGIN(qcncodecs)
Q_IMPORT_PLUGIN(qjpcodecs)
Q_IMPORT_PLUGIN(qtwcodecs)
Q_IMPORT_PLUGIN(qkrcodecs)
+#else
+#if defined(QT_QPA_PLATFORM_MINIMAL)
+Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin);
+#endif
+#if defined(QT_QPA_PLATFORM_XCB)
+Q_IMPORT_PLUGIN(QXcbIntegrationPlugin);
+#elif defined(QT_QPA_PLATFORM_WINDOWS)
+Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
+#elif defined(QT_QPA_PLATFORM_COCOA)
+Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin);
+#endif
+#endif
#endif
extern void noui_connect();
@@ -36,36 +49,59 @@ extern void noui_connect();
// This is all you need to run all the tests
int main(int argc, char *argv[])
{
- ECC_Start();
SetupEnvironment();
SetupNetworking();
SelectParams(CBaseChainParams::MAIN);
noui_connect();
+ ClearDatadirCache();
+ fs::path pathTemp = fs::temp_directory_path() / strprintf("test_bitcoin-qt_%lu_%i", (unsigned long)GetTime(), (int)GetRand(100000));
+ fs::create_directories(pathTemp);
+ gArgs.ForceSetArg("-datadir", pathTemp.string());
bool fInvalid = false;
+ // Prefer the "minimal" platform for the test instead of the normal default
+ // platform ("xcb", "windows", or "cocoa") so tests can't unintentionally
+ // interfere with any background GUIs and don't require extra resources.
+ #if defined(WIN32)
+ _putenv_s("QT_QPA_PLATFORM", "minimal");
+ #else
+ setenv("QT_QPA_PLATFORM", "minimal", 0);
+ #endif
+
// Don't remove this, it's needed to access
- // QCoreApplication:: in the tests
- QCoreApplication app(argc, argv);
+ // QApplication:: and QCoreApplication:: in the tests
+ QApplication app(argc, argv);
app.setApplicationName("Bitcoin-Qt-test");
SSL_library_init();
URITests test1;
- if (QTest::qExec(&test1) != 0)
+ if (QTest::qExec(&test1) != 0) {
fInvalid = true;
+ }
#ifdef ENABLE_WALLET
PaymentServerTests test2;
- if (QTest::qExec(&test2) != 0)
+ if (QTest::qExec(&test2) != 0) {
fInvalid = true;
+ }
#endif
RPCNestedTests test3;
- if (QTest::qExec(&test3) != 0)
+ if (QTest::qExec(&test3) != 0) {
fInvalid = true;
+ }
CompatTests test4;
- if (QTest::qExec(&test4) != 0)
+ if (QTest::qExec(&test4) != 0) {
fInvalid = true;
+ }
+#ifdef ENABLE_WALLET
+ WalletTests test5;
+ if (QTest::qExec(&test5) != 0) {
+ fInvalid = true;
+ }
+#endif
+
+ fs::remove_all(pathTemp);
- ECC_Stop();
return fInvalid;
}
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
new file mode 100644
index 0000000000..eeae58bd05
--- /dev/null
+++ b/src/qt/test/wallettests.cpp
@@ -0,0 +1,265 @@
+#include "wallettests.h"
+
+#include "qt/bitcoinamountfield.h"
+#include "qt/callback.h"
+#include "qt/optionsmodel.h"
+#include "qt/platformstyle.h"
+#include "qt/qvalidatedlineedit.h"
+#include "qt/sendcoinsdialog.h"
+#include "qt/sendcoinsentry.h"
+#include "qt/transactiontablemodel.h"
+#include "qt/transactionview.h"
+#include "qt/walletmodel.h"
+#include "test/test_bitcoin.h"
+#include "validation.h"
+#include "wallet/wallet.h"
+#include "qt/overviewpage.h"
+#include "qt/receivecoinsdialog.h"
+#include "qt/recentrequeststablemodel.h"
+#include "qt/receiverequestdialog.h"
+
+#include <QAbstractButton>
+#include <QAction>
+#include <QApplication>
+#include <QCheckBox>
+#include <QPushButton>
+#include <QTimer>
+#include <QVBoxLayout>
+#include <QTextEdit>
+#include <QListView>
+#include <QDialogButtonBox>
+
+namespace
+{
+//! Press "Ok" button in message box dialog.
+void ConfirmMessage(QString* text = nullptr)
+{
+ QTimer::singleShot(0, makeCallback([text](Callback* callback) {
+ for (QWidget* widget : QApplication::topLevelWidgets()) {
+ if (widget->inherits("QMessageBox")) {
+ QMessageBox* messageBox = qobject_cast<QMessageBox*>(widget);
+ if (text) *text = messageBox->text();
+ messageBox->defaultButton()->click();
+ }
+ }
+ delete callback;
+ }), SLOT(call()));
+}
+
+//! Press "Yes" or "Cancel" buttons in modal send confirmation dialog.
+void ConfirmSend(QString* text = nullptr, bool cancel = false)
+{
+ QTimer::singleShot(0, makeCallback([text, cancel](Callback* callback) {
+ for (QWidget* widget : QApplication::topLevelWidgets()) {
+ if (widget->inherits("SendConfirmationDialog")) {
+ SendConfirmationDialog* dialog = qobject_cast<SendConfirmationDialog*>(widget);
+ if (text) *text = dialog->text();
+ QAbstractButton* button = dialog->button(cancel ? QMessageBox::Cancel : QMessageBox::Yes);
+ button->setEnabled(true);
+ button->click();
+ }
+ }
+ delete callback;
+ }), SLOT(call()));
+}
+
+//! Send coins to address and return txid.
+uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDestination& address, CAmount amount, bool rbf)
+{
+ QVBoxLayout* entries = sendCoinsDialog.findChild<QVBoxLayout*>("entries");
+ SendCoinsEntry* entry = qobject_cast<SendCoinsEntry*>(entries->itemAt(0)->widget());
+ entry->findChild<QValidatedLineEdit*>("payTo")->setText(QString::fromStdString(EncodeDestination(address)));
+ entry->findChild<BitcoinAmountField*>("payAmount")->setValue(amount);
+ sendCoinsDialog.findChild<QFrame*>("frameFee")
+ ->findChild<QFrame*>("frameFeeSelection")
+ ->findChild<QCheckBox*>("optInRBF")
+ ->setCheckState(rbf ? Qt::Checked : Qt::Unchecked);
+ uint256 txid;
+ boost::signals2::scoped_connection c(wallet.NotifyTransactionChanged.connect([&txid](CWallet*, const uint256& hash, ChangeType status) {
+ if (status == CT_NEW) txid = hash;
+ }));
+ ConfirmSend();
+ QMetaObject::invokeMethod(&sendCoinsDialog, "on_sendButton_clicked");
+ return txid;
+}
+
+//! Find index of txid in transaction list.
+QModelIndex FindTx(const QAbstractItemModel& model, const uint256& txid)
+{
+ QString hash = QString::fromStdString(txid.ToString());
+ int rows = model.rowCount({});
+ for (int row = 0; row < rows; ++row) {
+ QModelIndex index = model.index(row, 0, {});
+ if (model.data(index, TransactionTableModel::TxHashRole) == hash) {
+ return index;
+ }
+ }
+ return {};
+}
+
+//! Request context menu (call method that is public in qt5, but protected in qt4).
+void RequestContextMenu(QWidget* widget)
+{
+ class Qt4Hack : public QWidget
+ {
+ public:
+ using QWidget::customContextMenuRequested;
+ };
+ static_cast<Qt4Hack*>(widget)->customContextMenuRequested({});
+}
+
+//! Invoke bumpfee on txid and check results.
+void BumpFee(TransactionView& view, const uint256& txid, bool expectDisabled, std::string expectError, bool cancel)
+{
+ QTableView* table = view.findChild<QTableView*>("transactionView");
+ QModelIndex index = FindTx(*table->selectionModel()->model(), txid);
+ QVERIFY2(index.isValid(), "Could not find BumpFee txid");
+
+ // Select row in table, invoke context menu, and make sure bumpfee action is
+ // enabled or disabled as expected.
+ QAction* action = view.findChild<QAction*>("bumpFeeAction");
+ table->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
+ action->setEnabled(expectDisabled);
+ RequestContextMenu(table);
+ QCOMPARE(action->isEnabled(), !expectDisabled);
+
+ action->setEnabled(true);
+ QString text;
+ if (expectError.empty()) {
+ ConfirmSend(&text, cancel);
+ } else {
+ ConfirmMessage(&text);
+ }
+ action->trigger();
+ QVERIFY(text.indexOf(QString::fromStdString(expectError)) != -1);
+}
+
+//! Simple qt wallet tests.
+//
+// Test widgets can be debugged interactively calling show() on them and
+// manually running the event loop, e.g.:
+//
+// sendCoinsDialog.show();
+// QEventLoop().exec();
+//
+// This also requires overriding the default minimal Qt platform:
+//
+// src/qt/test/test_bitcoin-qt -platform xcb # Linux
+// src/qt/test/test_bitcoin-qt -platform windows # Windows
+// src/qt/test/test_bitcoin-qt -platform cocoa # macOS
+void TestGUI()
+{
+ // Set up wallet and chain with 105 blocks (5 mature blocks for spending).
+ TestChain100Setup test;
+ for (int i = 0; i < 5; ++i) {
+ test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey()));
+ }
+ bitdb.MakeMock();
+ std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, "wallet_test.dat"));
+ CWallet wallet(std::move(dbw));
+ bool firstRun;
+ wallet.LoadWallet(firstRun);
+ {
+ LOCK(wallet.cs_wallet);
+ wallet.SetAddressBook(test.coinbaseKey.GetPubKey().GetID(), "", "receive");
+ wallet.AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey());
+ }
+ wallet.ScanForWalletTransactions(chainActive.Genesis(), true);
+ wallet.SetBroadcastTransactions(true);
+
+ // Create widgets for sending coins and listing transactions.
+ std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
+ SendCoinsDialog sendCoinsDialog(platformStyle.get());
+ TransactionView transactionView(platformStyle.get());
+ OptionsModel optionsModel;
+ WalletModel walletModel(platformStyle.get(), &wallet, &optionsModel);
+ sendCoinsDialog.setModel(&walletModel);
+ transactionView.setModel(&walletModel);
+
+ // Send two transactions, and verify they are added to transaction list.
+ TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel();
+ QCOMPARE(transactionTableModel->rowCount({}), 105);
+ uint256 txid1 = SendCoins(wallet, sendCoinsDialog, CKeyID(), 5 * COIN, false /* rbf */);
+ uint256 txid2 = SendCoins(wallet, sendCoinsDialog, CKeyID(), 10 * COIN, true /* rbf */);
+ QCOMPARE(transactionTableModel->rowCount({}), 107);
+ QVERIFY(FindTx(*transactionTableModel, txid1).isValid());
+ QVERIFY(FindTx(*transactionTableModel, txid2).isValid());
+
+ // Call bumpfee. Test disabled, canceled, enabled, then failing cases.
+ BumpFee(transactionView, txid1, true /* expect disabled */, "not BIP 125 replaceable" /* expected error */, false /* cancel */);
+ BumpFee(transactionView, txid2, false /* expect disabled */, {} /* expected error */, true /* cancel */);
+ BumpFee(transactionView, txid2, false /* expect disabled */, {} /* expected error */, false /* cancel */);
+ BumpFee(transactionView, txid2, true /* expect disabled */, "already bumped" /* expected error */, false /* cancel */);
+
+ // Check current balance on OverviewPage
+ OverviewPage overviewPage(platformStyle.get());
+ overviewPage.setWalletModel(&walletModel);
+ QLabel* balanceLabel = overviewPage.findChild<QLabel*>("labelBalance");
+ QString balanceText = balanceLabel->text();
+ int unit = walletModel.getOptionsModel()->getDisplayUnit();
+ CAmount balance = walletModel.getBalance();
+ QString balanceComparison = BitcoinUnits::formatWithUnit(unit, balance, false, BitcoinUnits::separatorAlways);
+ QCOMPARE(balanceText, balanceComparison);
+
+ // Check Request Payment button
+ ReceiveCoinsDialog receiveCoinsDialog(platformStyle.get());
+ receiveCoinsDialog.setModel(&walletModel);
+ RecentRequestsTableModel* requestTableModel = walletModel.getRecentRequestsTableModel();
+
+ // Label input
+ QLineEdit* labelInput = receiveCoinsDialog.findChild<QLineEdit*>("reqLabel");
+ labelInput->setText("TEST_LABEL_1");
+
+ // Amount input
+ BitcoinAmountField* amountInput = receiveCoinsDialog.findChild<BitcoinAmountField*>("reqAmount");
+ amountInput->setValue(1);
+
+ // Message input
+ QLineEdit* messageInput = receiveCoinsDialog.findChild<QLineEdit*>("reqMessage");
+ messageInput->setText("TEST_MESSAGE_1");
+ int initialRowCount = requestTableModel->rowCount({});
+ QPushButton* requestPaymentButton = receiveCoinsDialog.findChild<QPushButton*>("receiveButton");
+ requestPaymentButton->click();
+ for (QWidget* widget : QApplication::topLevelWidgets()) {
+ if (widget->inherits("ReceiveRequestDialog")) {
+ ReceiveRequestDialog* receiveRequestDialog = qobject_cast<ReceiveRequestDialog*>(widget);
+ QTextEdit* rlist = receiveRequestDialog->QObject::findChild<QTextEdit*>("outUri");
+ QString paymentText = rlist->toPlainText();
+ QStringList paymentTextList = paymentText.split('\n');
+ QCOMPARE(paymentTextList.at(0), QString("Payment information"));
+ QVERIFY(paymentTextList.at(1).indexOf(QString("URI: bitcoin:")) != -1);
+ QVERIFY(paymentTextList.at(2).indexOf(QString("Address:")) != -1);
+ QCOMPARE(paymentTextList.at(3), QString("Amount: 0.00000001 ") + QString::fromStdString(CURRENCY_UNIT));
+ QCOMPARE(paymentTextList.at(4), QString("Label: TEST_LABEL_1"));
+ QCOMPARE(paymentTextList.at(5), QString("Message: TEST_MESSAGE_1"));
+ }
+ }
+
+ // Clear button
+ QPushButton* clearButton = receiveCoinsDialog.findChild<QPushButton*>("clearButton");
+ clearButton->click();
+ QCOMPARE(labelInput->text(), QString(""));
+ QCOMPARE(amountInput->value(), CAmount(0));
+ QCOMPARE(messageInput->text(), QString(""));
+
+ // Check addition to history
+ int currentRowCount = requestTableModel->rowCount({});
+ QCOMPARE(currentRowCount, initialRowCount+1);
+
+ // Check Remove button
+ QTableView* table = receiveCoinsDialog.findChild<QTableView*>("recentRequestsView");
+ table->selectRow(currentRowCount-1);
+ QPushButton* removeRequestButton = receiveCoinsDialog.findChild<QPushButton*>("removeRequestButton");
+ removeRequestButton->click();
+ QCOMPARE(requestTableModel->rowCount({}), currentRowCount-1);
+
+ bitdb.Flush(true);
+ bitdb.Reset();
+}
+
+}
+
+void WalletTests::walletTests()
+{
+ TestGUI();
+}
diff --git a/src/qt/test/wallettests.h b/src/qt/test/wallettests.h
new file mode 100644
index 0000000000..342f7916c3
--- /dev/null
+++ b/src/qt/test/wallettests.h
@@ -0,0 +1,15 @@
+#ifndef BITCOIN_QT_TEST_WALLETTESTS_H
+#define BITCOIN_QT_TEST_WALLETTESTS_H
+
+#include <QObject>
+#include <QTest>
+
+class WalletTests : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void walletTests();
+};
+
+#endif // BITCOIN_QT_TEST_WALLETTESTS_H
diff --git a/src/qt/trafficgraphwidget.cpp b/src/qt/trafficgraphwidget.cpp
index 601d554c02..5bb863451f 100644
--- a/src/qt/trafficgraphwidget.cpp
+++ b/src/qt/trafficgraphwidget.cpp
@@ -47,13 +47,14 @@ int TrafficGraphWidget::getGraphRangeMins() const
void TrafficGraphWidget::paintPath(QPainterPath &path, QQueue<float> &samples)
{
- int h = height() - YMARGIN * 2, w = width() - XMARGIN * 2;
- int sampleCount = samples.size(), x = XMARGIN + w, y;
+ int sampleCount = samples.size();
if(sampleCount > 0) {
+ int h = height() - YMARGIN * 2, w = width() - XMARGIN * 2;
+ int x = XMARGIN + w;
path.moveTo(x, YMARGIN + h);
for(int i = 0; i < sampleCount; ++i) {
x = XMARGIN + w - w * i / DESIRED_SAMPLES;
- y = YMARGIN + h - (int)(h * samples.at(i) / fMax);
+ int y = YMARGIN + h - (int)(h * samples.at(i) / fMax);
path.lineTo(x, y);
}
path.lineTo(x, YMARGIN + h);
@@ -139,10 +140,10 @@ void TrafficGraphWidget::updateRates()
}
float tmax = 0.0f;
- Q_FOREACH(float f, vSamplesIn) {
+ for (float f : vSamplesIn) {
if(f > tmax) tmax = f;
}
- Q_FOREACH(float f, vSamplesOut) {
+ for (float f : vSamplesOut) {
if(f > tmax) tmax = f;
}
fMax = tmax;
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index 7e16cc9dd4..74f5c774a0 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -91,9 +91,8 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
if (nNet > 0)
{
// Credit
- if (CBitcoinAddress(rec->address).IsValid())
- {
- CTxDestination address = CBitcoinAddress(rec->address).Get();
+ CTxDestination address = DecodeDestination(rec->address);
+ if (IsValidDestination(address)) {
if (wallet->mapAddressBook.count(address))
{
strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
@@ -118,7 +117,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
// Online transaction
std::string strAddress = wtx.mapValue["to"];
strHTML += "<b>" + tr("To") + ":</b> ";
- CTxDestination dest = CBitcoinAddress(strAddress).Get();
+ CTxDestination dest = DecodeDestination(strAddress);
if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].name.empty())
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest].name) + " ";
strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>";
@@ -133,7 +132,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
// Coinbase
//
CAmount nUnmatured = 0;
- BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
+ for (const CTxOut& txout : wtx.tx->vout)
nUnmatured += wallet->GetCredit(txout, ISMINE_ALL);
strHTML += "<b>" + tr("Credit") + ":</b> ";
if (wtx.IsInMainChain())
@@ -152,14 +151,14 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
else
{
isminetype fAllFromMe = ISMINE_SPENDABLE;
- BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
+ for (const CTxIn& txin : wtx.tx->vin)
{
isminetype mine = wallet->IsMine(txin);
if(fAllFromMe > mine) fAllFromMe = mine;
}
isminetype fAllToMe = ISMINE_SPENDABLE;
- BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
+ for (const CTxOut& txout : wtx.tx->vout)
{
isminetype mine = wallet->IsMine(txout);
if(fAllToMe > mine) fAllToMe = mine;
@@ -173,7 +172,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
//
// Debit
//
- BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
+ for (const CTxOut& txout : wtx.tx->vout)
{
// Ignore change
isminetype toSelf = wallet->IsMine(txout);
@@ -189,7 +188,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
strHTML += "<b>" + tr("To") + ":</b> ";
if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty())
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " ";
- strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
+ strHTML += GUIUtil::HtmlEscape(EncodeDestination(address));
if(toSelf == ISMINE_SPENDABLE)
strHTML += " (own address)";
else if(toSelf & ISMINE_WATCH_ONLY)
@@ -221,10 +220,10 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
//
// Mixed debit transaction
//
- BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
+ for (const CTxIn& txin : wtx.tx->vin)
if (wallet->IsMine(txin))
strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "<br>";
- BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
+ for (const CTxOut& txout : wtx.tx->vout)
if (wallet->IsMine(txout))
strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout, ISMINE_ALL)) + "<br>";
}
@@ -245,14 +244,14 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
strHTML += "<b>" + tr("Output index") + ":</b> " + QString::number(rec->getOutputIndex()) + "<br>";
// Message from normal bitcoin:URI (bitcoin:123...?message=example)
- Q_FOREACH (const PAIRTYPE(std::string, std::string)& r, wtx.vOrderForm)
+ for (const std::pair<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:
//
- Q_FOREACH (const PAIRTYPE(std::string, std::string)& r, wtx.vOrderForm)
+ for (const std::pair<std::string, std::string>& r : wtx.vOrderForm)
{
if (r.first == "PaymentRequest")
{
@@ -273,13 +272,13 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
//
// Debug view
//
- if (fDebug)
+ if (logCategories != BCLog::NONE)
{
strHTML += "<hr><br>" + tr("Debug information") + "<br><br>";
- BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
+ for (const CTxIn& txin : wtx.tx->vin)
if(wallet->IsMine(txin))
strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "<br>";
- BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
+ for (const CTxOut& txout : wtx.tx->vout)
if(wallet->IsMine(txout))
strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout, ISMINE_ALL)) + "<br>";
@@ -289,23 +288,22 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
strHTML += "<br><b>" + tr("Inputs") + ":</b>";
strHTML += "<ul>";
- BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
+ for (const CTxIn& txin : wtx.tx->vin)
{
COutPoint prevout = txin.prevout;
- CCoins prev;
- if(pcoinsTip->GetCoins(prevout.hash, prev))
+ Coin prev;
+ if(pcoinsTip->GetCoin(prevout, prev))
{
- if (prevout.n < prev.vout.size())
{
strHTML += "<li>";
- const CTxOut &vout = prev.vout[prevout.n];
+ const CTxOut &vout = prev.out;
CTxDestination address;
if (ExtractDestination(vout.scriptPubKey, address))
{
if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty())
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " ";
- strHTML += QString::fromStdString(CBitcoinAddress(address).ToString());
+ strHTML += QString::fromStdString(EncodeDestination(address));
}
strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatHtmlWithUnit(unit, vout.nValue);
strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) & ISMINE_SPENDABLE ? tr("true") : tr("false")) + "</li>";
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index cbdedbf68b..d40ffd22cd 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -12,20 +12,13 @@
#include <stdint.h>
-#include <boost/foreach.hpp>
/* Return positive answer if transaction should be shown in list.
*/
bool TransactionRecord::showTransaction(const CWalletTx &wtx)
{
- if (wtx.IsCoinBase())
- {
- // Ensures we show generated coins / mined transactions at depth 1
- if (!wtx.IsInMainChain())
- {
- return false;
- }
- }
+ // There are currently no cases where we hide transactions, but
+ // we may want to use this in the future for things like RBF.
return true;
}
@@ -47,21 +40,22 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
//
// Credit
//
- BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
+ for(unsigned int i = 0; i < wtx.tx->vout.size(); i++)
{
+ const CTxOut& txout = wtx.tx->vout[i];
isminetype mine = wallet->IsMine(txout);
if(mine)
{
TransactionRecord sub(hash, nTime);
CTxDestination address;
- sub.idx = parts.size(); // sequence number
+ sub.idx = i; // vout index
sub.credit = txout.nValue;
sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY;
if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
{
// Received by Bitcoin Address
sub.type = TransactionRecord::RecvWithAddress;
- sub.address = CBitcoinAddress(address).ToString();
+ sub.address = EncodeDestination(address);
}
else
{
@@ -83,7 +77,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
{
bool involvesWatchAddress = false;
isminetype fAllFromMe = ISMINE_SPENDABLE;
- BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
+ for (const CTxIn& txin : wtx.tx->vin)
{
isminetype mine = wallet->IsMine(txin);
if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true;
@@ -91,7 +85,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
}
isminetype fAllToMe = ISMINE_SPENDABLE;
- BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
+ for (const CTxOut& txout : wtx.tx->vout)
{
isminetype mine = wallet->IsMine(txout);
if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true;
@@ -118,7 +112,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
{
const CTxOut& txout = wtx.tx->vout[nOut];
TransactionRecord sub(hash, nTime);
- sub.idx = parts.size();
+ sub.idx = nOut;
sub.involvesWatchAddress = involvesWatchAddress;
if(wallet->IsMine(txout))
@@ -133,7 +127,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
{
// Sent to Bitcoin Address
sub.type = TransactionRecord::SendToAddress;
- sub.address = CBitcoinAddress(address).ToString();
+ sub.address = EncodeDestination(address);
}
else
{
@@ -173,7 +167,7 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
// Determine transaction status
// Find the block the tx is in
- CBlockIndex* pindex = NULL;
+ CBlockIndex* pindex = nullptr;
BlockMap::iterator mi = mapBlockIndex.find(wtx.hashBlock);
if (mi != mapBlockIndex.end())
pindex = (*mi).second;
@@ -251,13 +245,13 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
status.status = TransactionStatus::Confirmed;
}
}
-
+ status.needsUpdate = false;
}
-bool TransactionRecord::statusUpdateNeeded()
+bool TransactionRecord::statusUpdateNeeded() const
{
AssertLockHeld(cs_main);
- return status.cur_num_blocks != chainActive.Height();
+ return status.cur_num_blocks != chainActive.Height() || status.needsUpdate;
}
QString TransactionRecord::getTxID() const
diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h
index 5aabbbffa8..a26e676142 100644
--- a/src/qt/transactionrecord.h
+++ b/src/qt/transactionrecord.h
@@ -61,6 +61,8 @@ public:
/** Current number of blocks (to know whether cached status is still valid) */
int cur_num_blocks;
+
+ bool needsUpdate;
};
/** UI model for a transaction. A core transaction can be represented by multiple UI transactions if it has
@@ -138,7 +140,7 @@ public:
/** Return whether a status update is needed.
*/
- bool statusUpdateNeeded();
+ bool statusUpdateNeeded() const;
};
#endif // BITCOIN_QT_TRANSACTIONRECORD_H
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index 61466c8ed1..59cef555b1 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -26,8 +26,6 @@
#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 */
@@ -145,7 +143,7 @@ public:
{
parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex+toInsert.size()-1);
int insert_idx = lowerIndex;
- Q_FOREACH(const TransactionRecord &rec, toInsert)
+ for (const TransactionRecord &rec : toInsert)
{
cachedWallet.insert(insert_idx, rec);
insert_idx += 1;
@@ -168,6 +166,10 @@ public:
case CT_UPDATED:
// Miscellaneous updates -- nothing to do, status update will take care of this, and is only computed for
// visible transactions.
+ for (int i = lowerIndex; i < upperIndex; i++) {
+ TransactionRecord *rec = &cachedWallet[i];
+ rec->status.needsUpdate = true;
+ }
break;
}
}
diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h
index 80aeb64c41..b1f81498b2 100644
--- a/src/qt/transactiontablemodel.h
+++ b/src/qt/transactiontablemodel.h
@@ -79,7 +79,7 @@ public:
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 = QModelIndex()) const;
- bool processingQueuedTransactions() { return fProcessingQueuedTransactions; }
+ bool processingQueuedTransactions() const { return fProcessingQueuedTransactions; }
private:
CWallet* wallet;
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index 30f4db9450..39dfdb587c 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -11,6 +11,7 @@
#include "guiutil.h"
#include "optionsmodel.h"
#include "platformstyle.h"
+#include "sendcoinsdialog.h"
#include "transactiondescdialog.h"
#include "transactionfilterproxy.h"
#include "transactionrecord.h"
@@ -32,12 +33,13 @@
#include <QScrollBar>
#include <QSignalMapper>
#include <QTableView>
+#include <QTimer>
#include <QUrl>
#include <QVBoxLayout>
TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *parent) :
QWidget(parent), model(0), transactionProxyModel(0),
- transactionView(0), abandonAction(0), columnResizingFixer(0)
+ transactionView(0), abandonAction(0), bumpFeeAction(0), columnResizingFixer(0)
{
// Build filter row
setContentsMargins(0,0,0,0);
@@ -111,6 +113,17 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
amountWidget->setValidator(new QDoubleValidator(0, 1e20, 8, this));
hlayout->addWidget(amountWidget);
+ // Delay before filtering transactions in ms
+ static const int input_filter_delay = 200;
+
+ QTimer* amount_typing_delay = new QTimer(this);
+ amount_typing_delay->setSingleShot(true);
+ amount_typing_delay->setInterval(input_filter_delay);
+
+ QTimer* prefix_typing_delay = new QTimer(this);
+ prefix_typing_delay->setSingleShot(true);
+ prefix_typing_delay->setInterval(input_filter_delay);
+
QVBoxLayout *vlayout = new QVBoxLayout(this);
vlayout->setContentsMargins(0,0,0,0);
vlayout->setSpacing(0);
@@ -135,9 +148,12 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
view->installEventFilter(this);
transactionView = view;
+ transactionView->setObjectName("transactionView");
// Actions
abandonAction = new QAction(tr("Abandon transaction"), this);
+ bumpFeeAction = new QAction(tr("Increase transaction fee"), this);
+ bumpFeeAction->setObjectName("bumpFeeAction");
QAction *copyAddressAction = new QAction(tr("Copy address"), this);
QAction *copyLabelAction = new QAction(tr("Copy label"), this);
QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
@@ -148,6 +164,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
QAction *showDetailsAction = new QAction(tr("Show transaction details"), this);
contextMenu = new QMenu(this);
+ contextMenu->setObjectName("contextMenu");
contextMenu->addAction(copyAddressAction);
contextMenu->addAction(copyLabelAction);
contextMenu->addAction(copyAmountAction);
@@ -156,6 +173,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
contextMenu->addAction(copyTxPlainText);
contextMenu->addAction(showDetailsAction);
contextMenu->addSeparator();
+ contextMenu->addAction(bumpFeeAction);
contextMenu->addAction(abandonAction);
contextMenu->addAction(editLabelAction);
@@ -167,12 +185,15 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
connect(dateWidget, SIGNAL(activated(int)), this, SLOT(chooseDate(int)));
connect(typeWidget, SIGNAL(activated(int)), this, SLOT(chooseType(int)));
connect(watchOnlyWidget, SIGNAL(activated(int)), this, SLOT(chooseWatchonly(int)));
- connect(addressWidget, SIGNAL(textChanged(QString)), this, SLOT(changedPrefix(QString)));
- connect(amountWidget, SIGNAL(textChanged(QString)), this, SLOT(changedAmount(QString)));
+ connect(amountWidget, SIGNAL(textChanged(QString)), amount_typing_delay, SLOT(start()));
+ connect(amount_typing_delay, SIGNAL(timeout()), this, SLOT(changedAmount()));
+ connect(addressWidget, SIGNAL(textChanged(QString)), prefix_typing_delay, SLOT(start()));
+ connect(prefix_typing_delay, SIGNAL(timeout()), this, SLOT(changedPrefix()));
connect(view, SIGNAL(doubleClicked(QModelIndex)), this, SIGNAL(doubleClicked(QModelIndex)));
connect(view, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint)));
+ connect(bumpFeeAction, SIGNAL(triggered()), this, SLOT(bumpFee()));
connect(abandonAction, SIGNAL(triggered()), this, SLOT(abandonTx()));
connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress()));
connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel()));
@@ -305,20 +326,19 @@ void TransactionView::chooseWatchonly(int idx)
(TransactionFilterProxy::WatchOnlyFilter)watchOnlyWidget->itemData(idx).toInt());
}
-void TransactionView::changedPrefix(const QString &prefix)
+void TransactionView::changedPrefix()
{
if(!transactionProxyModel)
return;
- transactionProxyModel->setAddressPrefix(prefix);
+ transactionProxyModel->setAddressPrefix(addressWidget->text());
}
-void TransactionView::changedAmount(const QString &amount)
+void TransactionView::changedAmount()
{
if(!transactionProxyModel)
return;
CAmount amount_parsed = 0;
- if(BitcoinUnits::parse(model->getOptionsModel()->getDisplayUnit(), amount, &amount_parsed))
- {
+ if (BitcoinUnits::parse(model->getOptionsModel()->getDisplayUnit(), amountWidget->text(), &amount_parsed)) {
transactionProxyModel->setMinAmount(amount_parsed);
}
else
@@ -329,10 +349,14 @@ void TransactionView::changedAmount(const QString &amount)
void TransactionView::exportClicked()
{
+ if (!model || !model->getOptionsModel()) {
+ return;
+ }
+
// CSV is currently the only supported format
QString filename = GUIUtil::getSaveFileName(this,
tr("Export Transaction History"), QString(),
- tr("Comma separated file (*.csv)"), NULL);
+ tr("Comma separated file (*.csv)"), nullptr);
if (filename.isNull())
return;
@@ -372,10 +396,11 @@ void TransactionView::contextualMenu(const QPoint &point)
uint256 hash;
hash.SetHex(selection.at(0).data(TransactionTableModel::TxHashRole).toString().toStdString());
abandonAction->setEnabled(model->transactionCanBeAbandoned(hash));
+ bumpFeeAction->setEnabled(model->transactionCanBeBumped(hash));
if(index.isValid())
{
- contextMenu->exec(QCursor::pos());
+ contextMenu->popup(transactionView->viewport()->mapToGlobal(point));
}
}
@@ -397,6 +422,24 @@ void TransactionView::abandonTx()
model->getTransactionTableModel()->updateTransaction(hashQStr, CT_UPDATED, false);
}
+void TransactionView::bumpFee()
+{
+ if(!transactionView || !transactionView->selectionModel())
+ return;
+ QModelIndexList selection = transactionView->selectionModel()->selectedRows(0);
+
+ // get the hash from the TxHashRole (QVariant / QString)
+ uint256 hash;
+ QString hashQStr = selection.at(0).data(TransactionTableModel::TxHashRole).toString();
+ hash.SetHex(hashQStr.toStdString());
+
+ // Bump tx fee over the walletModel
+ if (model->bumpFee(hash)) {
+ // Update the table
+ model->getTransactionTableModel()->updateTransaction(hashQStr, CT_UPDATED, true);
+ }
+}
+
void TransactionView::copyAddress()
{
GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::AddressRole);
diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h
index 595701cdd9..5b4cfd4a88 100644
--- a/src/qt/transactionview.h
+++ b/src/qt/transactionview.h
@@ -76,6 +76,7 @@ private:
QDateTimeEdit *dateFrom;
QDateTimeEdit *dateTo;
QAction *abandonAction;
+ QAction *bumpFeeAction;
QWidget *createDateRangeWidget();
@@ -99,6 +100,7 @@ private Q_SLOTS:
void openThirdPartyTxUrl(QString url);
void updateWatchOnlyColumn(bool fHaveWatchOnly);
void abandonTx();
+ void bumpFee();
Q_SIGNALS:
void doubleClicked(const QModelIndex&);
@@ -110,8 +112,8 @@ public Q_SLOTS:
void chooseDate(int idx);
void chooseType(int idx);
void chooseWatchonly(int idx);
- void changedPrefix(const QString &prefix);
- void changedAmount(const QString &amount);
+ void changedAmount();
+ void changedPrefix();
void exportClicked();
void focusTransaction(const QModelIndex&);
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index 70efe27990..5d8c23d13c 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -39,7 +39,7 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) :
QString version = tr(PACKAGE_NAME) + " " + tr("version") + " " + QString::fromStdString(FormatFullVersion());
/* On x86 add a bit specifier to the version so that users can distinguish between
- * 32 and 64 bit builds. On other architectures, 32/64 bit may be more ambigious.
+ * 32 and 64 bit builds. On other architectures, 32/64 bit may be more ambiguous.
*/
#if defined(__x86_64__)
version += " " + tr("(%1-bit)").arg(64);
@@ -78,7 +78,7 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) :
cursor.insertBlock();
std::string strUsage = HelpMessage(HMM_BITCOIN_QT);
- const bool showDebug = GetBoolArg("-help-debug", false);
+ const bool showDebug = gArgs.GetBoolArg("-help-debug", false);
strUsage += HelpMessageGroup(tr("UI Options:").toStdString());
if (showDebug) {
strUsage += HelpMessageOpt("-allowselfsignedrootcertificates", strprintf("Allow self signed root certificates (default: %u)", DEFAULT_SELFSIGNED_ROOTCERTS));
@@ -106,7 +106,7 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) :
QTextCharFormat bold;
bold.setFontWeight(QFont::Bold);
- Q_FOREACH (const QString &line, coreOptions.split("\n")) {
+ for (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 1b6781c5fc..738eeed136 100644
--- a/src/qt/utilitydialog.h
+++ b/src/qt/utilitydialog.h
@@ -9,7 +9,6 @@
#include <QObject>
class BitcoinGUI;
-class ClientModel;
namespace Ui {
class HelpMessageDialog;
@@ -42,7 +41,7 @@ class ShutdownWindow : public QWidget
Q_OBJECT
public:
- ShutdownWindow(QWidget *parent=0, Qt::WindowFlags f=0);
+ explicit ShutdownWindow(QWidget *parent=0, Qt::WindowFlags f=0);
static QWidget *showShutdownWindow(BitcoinGUI *window);
protected:
diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp
index f3183320f0..714a594318 100644
--- a/src/qt/walletframe.cpp
+++ b/src/qt/walletframe.cpp
@@ -7,6 +7,7 @@
#include "bitcoingui.h"
#include "walletview.h"
+#include <cassert>
#include <cstdio>
#include <QHBoxLayout>
@@ -69,6 +70,7 @@ bool WalletFrame::setCurrentWallet(const QString& name)
WalletView *walletView = mapWalletViews.value(name);
walletStack->setCurrentWidget(walletView);
+ assert(walletView);
walletView->updateEncryptionStatus();
return true;
}
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 0a5a7c3e9f..53b1c2967c 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -8,27 +8,34 @@
#include "consensus/validation.h"
#include "guiconstants.h"
#include "guiutil.h"
+#include "optionsmodel.h"
#include "paymentserver.h"
#include "recentrequeststablemodel.h"
+#include "sendcoinsdialog.h"
#include "transactiontablemodel.h"
#include "base58.h"
+#include "chain.h"
#include "keystore.h"
#include "validation.h"
#include "net.h" // for g_connman
+#include "policy/fees.h"
+#include "policy/rbf.h"
#include "sync.h"
#include "ui_interface.h"
#include "util.h" // for GetBoolArg
+#include "wallet/coincontrol.h"
+#include "wallet/feebumper.h"
#include "wallet/wallet.h"
#include "wallet/walletdb.h" // for BackupWallet
#include <stdint.h>
#include <QDebug>
+#include <QMessageBox>
#include <QSet>
#include <QTimer>
-#include <boost/foreach.hpp>
WalletModel::WalletModel(const PlatformStyle *platformStyle, CWallet *_wallet, OptionsModel *_optionsModel, QObject *parent) :
QObject(parent), wallet(_wallet), optionsModel(_optionsModel), addressTableModel(0),
@@ -62,14 +69,7 @@ CAmount WalletModel::getBalance(const CCoinControl *coinControl) const
{
if (coinControl)
{
- CAmount nBalance = 0;
- std::vector<COutput> vCoins;
- wallet->AvailableCoins(vCoins, true, coinControl);
- BOOST_FOREACH(const COutput& out, vCoins)
- if(out.fSpendable)
- nBalance += out.tx->tx->vout[out.i].nValue;
-
- return nBalance;
+ return wallet->GetAvailableBalance(coinControl);
}
return wallet->GetBalance();
@@ -188,11 +188,10 @@ void WalletModel::updateWatchOnlyFlag(bool fHaveWatchonly)
bool WalletModel::validateAddress(const QString &address)
{
- CBitcoinAddress addressParsed(address.toStdString());
- return addressParsed.IsValid();
+ return IsValidDestinationString(address.toStdString());
}
-WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl *coinControl)
+WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl)
{
CAmount total = 0;
bool fSubtractFeeFromAmount = false;
@@ -208,7 +207,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
int nAddresses = 0;
// Pre-check input data for validity
- Q_FOREACH(const SendCoinsRecipient &rcp, recipients)
+ for (const SendCoinsRecipient &rcp : recipients)
{
if (rcp.fSubtractFeeFromAmount)
fSubtractFeeFromAmount = true;
@@ -247,7 +246,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
setAddress.insert(rcp.address);
++nAddresses;
- CScript scriptPubKey = GetScriptForDestination(CBitcoinAddress(rcp.address.toStdString()).Get());
+ CScript scriptPubKey = GetScriptForDestination(DecodeDestination(rcp.address.toStdString()));
CRecipient recipient = {scriptPubKey, rcp.amount, rcp.fSubtractFeeFromAmount};
vecSend.push_back(recipient);
@@ -259,7 +258,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
return DuplicateAddress;
}
- CAmount nBalance = getBalance(coinControl);
+ CAmount nBalance = getBalance(&coinControl);
if(total > nBalance)
{
@@ -311,7 +310,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
LOCK2(cs_main, wallet->cs_wallet);
CWalletTx *newTx = transaction.getTransaction();
- Q_FOREACH(const SendCoinsRecipient &rcp, transaction.getRecipients())
+ for (const SendCoinsRecipient &rcp : transaction.getRecipients())
{
if (rcp.paymentRequest.IsInitialized())
{
@@ -340,15 +339,15 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
transaction_array.append(&(ssTx[0]), ssTx.size());
}
- // Add addresses / update labels that we've sent to to the address book,
+ // Add addresses / update labels that we've sent to the address book,
// and emit coinsSent signal for each recipient
- Q_FOREACH(const SendCoinsRecipient &rcp, transaction.getRecipients())
+ for (const SendCoinsRecipient &rcp : transaction.getRecipients())
{
// Don't touch the address book when we have a payment request
if (!rcp.paymentRequest.IsInitialized())
{
std::string strAddress = rcp.address.toStdString();
- CTxDestination dest = CBitcoinAddress(strAddress).Get();
+ CTxDestination dest = DecodeDestination(strAddress);
std::string strLabel = rcp.label.toStdString();
{
LOCK(wallet->cs_wallet);
@@ -464,7 +463,7 @@ static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet,
const CTxDestination &address, const std::string &label, bool isMine,
const std::string &purpose, ChangeType status)
{
- QString strAddress = QString::fromStdString(CBitcoinAddress(address).ToString());
+ QString strAddress = QString::fromStdString(EncodeDestination(address));
QString strLabel = QString::fromStdString(label);
QString strPurpose = QString::fromStdString(purpose);
@@ -561,9 +560,9 @@ bool WalletModel::getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
return wallet->GetPubKey(address, vchPubKeyOut);
}
-bool WalletModel::havePrivKey(const CKeyID &address) const
+bool WalletModel::IsSpendable(const CTxDestination& dest) const
{
- return wallet->HaveKey(address);
+ return IsMine(*wallet, dest) & ISMINE_SPENDABLE;
}
bool WalletModel::getPrivKey(const CKeyID &address, CKey& vchPrivKeyOut) const
@@ -575,12 +574,13 @@ bool WalletModel::getPrivKey(const CKeyID &address, CKey& vchPrivKeyOut) const
void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vector<COutput>& vOutputs)
{
LOCK2(cs_main, wallet->cs_wallet);
- BOOST_FOREACH(const COutPoint& outpoint, vOutpoints)
+ for (const COutPoint& outpoint : vOutpoints)
{
- if (!wallet->mapWallet.count(outpoint.hash)) continue;
- int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
+ auto it = wallet->mapWallet.find(outpoint.hash);
+ if (it == wallet->mapWallet.end()) continue;
+ int nDepth = it->second.GetDepthInMainChain();
if (nDepth < 0) continue;
- COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true, true);
+ COutput out(&it->second, outpoint.n, nDepth, true /* spendable */, true /* solvable */, true /* safe */);
vOutputs.push_back(out);
}
}
@@ -594,38 +594,11 @@ bool WalletModel::isSpent(const COutPoint& outpoint) const
// AvailableCoins + LockedCoins grouped by wallet address (put change in one group with wallet address)
void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins) const
{
- std::vector<COutput> vCoins;
- wallet->AvailableCoins(vCoins);
-
- LOCK2(cs_main, wallet->cs_wallet); // ListLockedCoins, mapWallet
- std::vector<COutPoint> vLockedCoins;
- wallet->ListLockedCoins(vLockedCoins);
-
- // add locked coins
- BOOST_FOREACH(const COutPoint& outpoint, vLockedCoins)
- {
- if (!wallet->mapWallet.count(outpoint.hash)) continue;
- int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
- if (nDepth < 0) continue;
- COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true, true);
- if (outpoint.n < out.tx->tx->vout.size() && wallet->IsMine(out.tx->tx->vout[outpoint.n]) == ISMINE_SPENDABLE)
- vCoins.push_back(out);
- }
-
- BOOST_FOREACH(const COutput& out, vCoins)
- {
- COutput cout = out;
-
- while (wallet->IsChange(cout.tx->tx->vout[cout.i]) && cout.tx->tx->vin.size() > 0 && wallet->IsMine(cout.tx->tx->vin[0]))
- {
- if (!wallet->mapWallet.count(cout.tx->tx->vin[0].prevout.hash)) break;
- cout = COutput(&wallet->mapWallet[cout.tx->tx->vin[0].prevout.hash], cout.tx->tx->vin[0].prevout.n, 0, true, true);
+ for (auto& group : wallet->ListCoins()) {
+ auto& resultGroup = mapCoins[QString::fromStdString(EncodeDestination(group.first))];
+ for (auto& coin : group.second) {
+ resultGroup.emplace_back(std::move(coin));
}
-
- CTxDestination address;
- if(!out.fSpendable || !ExtractDestination(cout.tx->tx->vout[cout.i].scriptPubKey, address))
- continue;
- mapCoins[QString::fromStdString(CBitcoinAddress(address).ToString())].push_back(out);
}
}
@@ -655,16 +628,12 @@ void WalletModel::listLockedCoins(std::vector<COutPoint>& vOutpts)
void WalletModel::loadReceiveRequests(std::vector<std::string>& vReceiveRequests)
{
- LOCK(wallet->cs_wallet);
- BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, wallet->mapAddressBook)
- BOOST_FOREACH(const PAIRTYPE(std::string, std::string)& item2, item.second.destdata)
- if (item2.first.size() > 2 && item2.first.substr(0,2) == "rr") // receive request
- vReceiveRequests.push_back(item2.second);
+ vReceiveRequests = wallet->GetDestValues("rr"); // receive request
}
bool WalletModel::saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest)
{
- CTxDestination dest = CBitcoinAddress(sAddress).Get();
+ CTxDestination dest = DecodeDestination(sAddress);
std::stringstream ss;
ss << nId;
@@ -679,11 +648,7 @@ bool WalletModel::saveReceiveRequest(const std::string &sAddress, const int64_t
bool WalletModel::transactionCanBeAbandoned(uint256 hash) const
{
- LOCK2(cs_main, wallet->cs_wallet);
- const CWalletTx *wtx = wallet->GetWalletTx(hash);
- if (!wtx || wtx->isAbandoned() || wtx->GetDepthInMainChain() > 0 || wtx->InMempool())
- return false;
- return true;
+ return wallet->TransactionCanBeAbandoned(hash);
}
bool WalletModel::abandonTransaction(uint256 hash) const
@@ -692,9 +657,89 @@ bool WalletModel::abandonTransaction(uint256 hash) const
return wallet->AbandonTransaction(hash);
}
+bool WalletModel::transactionCanBeBumped(uint256 hash) const
+{
+ LOCK2(cs_main, wallet->cs_wallet);
+ const CWalletTx *wtx = wallet->GetWalletTx(hash);
+ return wtx && SignalsOptInRBF(*wtx) && !wtx->mapValue.count("replaced_by_txid");
+}
+
+bool WalletModel::bumpFee(uint256 hash)
+{
+ std::unique_ptr<CFeeBumper> feeBump;
+ {
+ CCoinControl coin_control;
+ coin_control.signalRbf = true;
+ LOCK2(cs_main, wallet->cs_wallet);
+ feeBump.reset(new CFeeBumper(wallet, hash, coin_control, 0));
+ }
+ if (feeBump->getResult() != BumpFeeResult::OK)
+ {
+ QMessageBox::critical(0, tr("Fee bump error"), tr("Increasing transaction fee failed") + "<br />(" +
+ (feeBump->getErrors().size() ? QString::fromStdString(feeBump->getErrors()[0]) : "") +")");
+ return false;
+ }
+
+ // allow a user based fee verification
+ QString questionString = tr("Do you want to increase the fee?");
+ questionString.append("<br />");
+ CAmount oldFee = feeBump->getOldFee();
+ CAmount newFee = feeBump->getNewFee();
+ questionString.append("<table style=\"text-align: left;\">");
+ questionString.append("<tr><td>");
+ questionString.append(tr("Current fee:"));
+ questionString.append("</td><td>");
+ questionString.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), oldFee));
+ questionString.append("</td></tr><tr><td>");
+ questionString.append(tr("Increase:"));
+ questionString.append("</td><td>");
+ questionString.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), newFee - oldFee));
+ questionString.append("</td></tr><tr><td>");
+ questionString.append(tr("New fee:"));
+ questionString.append("</td><td>");
+ questionString.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), newFee));
+ questionString.append("</td></tr></table>");
+ SendConfirmationDialog confirmationDialog(tr("Confirm fee bump"), questionString);
+ confirmationDialog.exec();
+ QMessageBox::StandardButton retval = (QMessageBox::StandardButton)confirmationDialog.result();
+
+ // cancel sign&broadcast if users doesn't want to bump the fee
+ if (retval != QMessageBox::Yes) {
+ return false;
+ }
+
+ WalletModel::UnlockContext ctx(requestUnlock());
+ if(!ctx.isValid())
+ {
+ return false;
+ }
+
+ // sign bumped transaction
+ bool res = false;
+ {
+ LOCK2(cs_main, wallet->cs_wallet);
+ res = feeBump->signTransaction(wallet);
+ }
+ if (!res) {
+ QMessageBox::critical(0, tr("Fee bump error"), tr("Can't sign transaction."));
+ return false;
+ }
+ // commit the bumped transaction
+ {
+ LOCK2(cs_main, wallet->cs_wallet);
+ res = feeBump->commit(wallet);
+ }
+ if(!res) {
+ QMessageBox::critical(0, tr("Fee bump error"), tr("Could not commit transaction") + "<br />(" +
+ QString::fromStdString(feeBump->getErrors()[0])+")");
+ return false;
+ }
+ return true;
+}
+
bool WalletModel::isWalletEnabled()
{
- return !GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET);
+ return !gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET);
}
bool WalletModel::hdEnabled() const
@@ -706,3 +751,8 @@ int WalletModel::getDefaultConfirmTarget() const
{
return nTxConfirmTarget;
}
+
+bool WalletModel::getDefaultWalletRbf() const
+{
+ return fWalletRbf;
+}
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index cd7585635f..05733f8272 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -129,7 +129,7 @@ public:
TransactionTableModel *getTransactionTableModel();
RecentRequestsTableModel *getRecentRequestsTableModel();
- CAmount getBalance(const CCoinControl *coinControl = NULL) const;
+ CAmount getBalance(const CCoinControl *coinControl = nullptr) const;
CAmount getUnconfirmedBalance() const;
CAmount getImmatureBalance() const;
bool haveWatchOnly() const;
@@ -154,7 +154,7 @@ public:
};
// prepare transaction for getting txfee before sending coins
- SendCoinsReturn prepareTransaction(WalletModelTransaction &transaction, const CCoinControl *coinControl = NULL);
+ SendCoinsReturn prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl);
// Send coins to a list of recipients
SendCoinsReturn sendCoins(WalletModelTransaction &transaction);
@@ -190,7 +190,7 @@ public:
UnlockContext requestUnlock();
bool getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const;
- bool havePrivKey(const CKeyID &address) const;
+ bool IsSpendable(const CTxDestination& dest) const;
bool getPrivKey(const CKeyID &address, CKey& vchPrivKeyOut) const;
void getOutputs(const std::vector<COutPoint>& vOutpoints, std::vector<COutput>& vOutputs);
bool isSpent(const COutPoint& outpoint) const;
@@ -207,12 +207,17 @@ public:
bool transactionCanBeAbandoned(uint256 hash) const;
bool abandonTransaction(uint256 hash) const;
+ bool transactionCanBeBumped(uint256 hash) const;
+ bool bumpFee(uint256 hash);
+
static bool isWalletEnabled();
bool hdEnabled() const;
int getDefaultConfirmTarget() const;
+ bool getDefaultWalletRbf() const;
+
private:
CWallet *wallet;
bool fHaveWatchOnly;
diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp
index b4445c8166..eae2c27f8a 100644
--- a/src/qt/walletmodeltransaction.cpp
+++ b/src/qt/walletmodeltransaction.cpp
@@ -22,12 +22,12 @@ WalletModelTransaction::~WalletModelTransaction()
delete walletTransaction;
}
-QList<SendCoinsRecipient> WalletModelTransaction::getRecipients()
+QList<SendCoinsRecipient> WalletModelTransaction::getRecipients() const
{
return recipients;
}
-CWalletTx *WalletModelTransaction::getTransaction()
+CWalletTx *WalletModelTransaction::getTransaction() const
{
return walletTransaction;
}
@@ -37,7 +37,7 @@ unsigned int WalletModelTransaction::getTransactionSize()
return (!walletTransaction ? 0 : ::GetVirtualTransactionSize(*walletTransaction));
}
-CAmount WalletModelTransaction::getTransactionFee()
+CAmount WalletModelTransaction::getTransactionFee() const
{
return fee;
}
@@ -79,10 +79,10 @@ void WalletModelTransaction::reassignAmounts(int nChangePosRet)
}
}
-CAmount WalletModelTransaction::getTotalTransactionAmount()
+CAmount WalletModelTransaction::getTotalTransactionAmount() const
{
CAmount totalTransactionAmount = 0;
- Q_FOREACH(const SendCoinsRecipient &rcp, recipients)
+ for (const SendCoinsRecipient &rcp : recipients)
{
totalTransactionAmount += rcp.amount;
}
diff --git a/src/qt/walletmodeltransaction.h b/src/qt/walletmodeltransaction.h
index 64922efada..d7ecd7aa8c 100644
--- a/src/qt/walletmodeltransaction.h
+++ b/src/qt/walletmodeltransaction.h
@@ -22,15 +22,15 @@ public:
explicit WalletModelTransaction(const QList<SendCoinsRecipient> &recipients);
~WalletModelTransaction();
- QList<SendCoinsRecipient> getRecipients();
+ QList<SendCoinsRecipient> getRecipients() const;
- CWalletTx *getTransaction();
+ CWalletTx *getTransaction() const;
unsigned int getTransactionSize();
void setTransactionFee(const CAmount& newFee);
- CAmount getTransactionFee();
+ CAmount getTransactionFee() const;
- CAmount getTotalTransactionAmount();
+ CAmount getTotalTransactionAmount() const;
void newPossibleKeyChange(CWallet *wallet);
CReserveKey *getPossibleKeyChange();
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index 4a18c0bd4d..971f5e0e1a 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -246,7 +246,7 @@ void WalletView::backupWallet()
{
QString filename = GUIUtil::getSaveFileName(this,
tr("Backup Wallet"), QString(),
- tr("Wallet Data (*.dat)"), NULL);
+ tr("Wallet Data (*.dat)"), nullptr);
if (filename.isEmpty())
return;
diff --git a/src/qt/winshutdownmonitor.cpp b/src/qt/winshutdownmonitor.cpp
index d6f40c38b8..d78d9a2358 100644
--- a/src/qt/winshutdownmonitor.cpp
+++ b/src/qt/winshutdownmonitor.cpp
@@ -57,7 +57,7 @@ void WinShutdownMonitor::registerShutdownBlockReason(const QString& strReason, c
{
typedef BOOL (WINAPI *PSHUTDOWNBRCREATE)(HWND, LPCWSTR);
PSHUTDOWNBRCREATE shutdownBRCreate = (PSHUTDOWNBRCREATE)GetProcAddress(GetModuleHandleA("User32.dll"), "ShutdownBlockReasonCreate");
- if (shutdownBRCreate == NULL) {
+ if (shutdownBRCreate == nullptr) {
qWarning() << "registerShutdownBlockReason: GetProcAddress for ShutdownBlockReasonCreate failed";
return;
}
diff --git a/src/random.cpp b/src/random.cpp
index 6634019bea..7e0e94439e 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -16,31 +16,115 @@
#include <stdlib.h>
#include <limits>
+#include <chrono>
+#include <thread>
#ifndef WIN32
#include <sys/time.h>
#endif
+#ifdef HAVE_SYS_GETRANDOM
+#include <sys/syscall.h>
+#include <linux/random.h>
+#endif
+#if defined(HAVE_GETENTROPY) || (defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX))
+#include <unistd.h>
+#endif
+#if defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX)
+#include <sys/random.h>
+#endif
+#ifdef HAVE_SYSCTL_ARND
+#include <sys/sysctl.h>
+#endif
+
+#include <mutex>
+
+#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
+#include <cpuid.h>
+#endif
+
#include <openssl/err.h>
#include <openssl/rand.h>
-static void RandFailure()
+[[noreturn]] static void RandFailure()
{
LogPrintf("Failed to read randomness, aborting\n");
- abort();
+ std::abort();
}
static inline int64_t GetPerformanceCounter()
{
- int64_t nCounter = 0;
-#ifdef WIN32
- QueryPerformanceCounter((LARGE_INTEGER*)&nCounter);
+ // Read the hardware time stamp counter when available.
+ // See https://en.wikipedia.org/wiki/Time_Stamp_Counter for more information.
+#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
+ return __rdtsc();
+#elif !defined(_MSC_VER) && defined(__i386__)
+ uint64_t r = 0;
+ __asm__ volatile ("rdtsc" : "=A"(r)); // Constrain the r variable to the eax:edx pair.
+ return r;
+#elif !defined(_MSC_VER) && (defined(__x86_64__) || defined(__amd64__))
+ uint64_t r1 = 0, r2 = 0;
+ __asm__ volatile ("rdtsc" : "=a"(r1), "=d"(r2)); // Constrain r1 to rax and r2 to rdx.
+ return (r2 << 32) | r1;
#else
- timeval t;
- gettimeofday(&t, NULL);
- nCounter = (int64_t)(t.tv_sec * 1000000 + t.tv_usec);
+ // Fall back to using C++11 clock (usually microsecond or nanosecond precision)
+ return std::chrono::high_resolution_clock::now().time_since_epoch().count();
#endif
- return nCounter;
+}
+
+
+#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
+static std::atomic<bool> hwrand_initialized{false};
+static bool rdrand_supported = false;
+static constexpr uint32_t CPUID_F1_ECX_RDRAND = 0x40000000;
+static void RDRandInit()
+{
+ uint32_t eax, ebx, ecx, edx;
+ if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) && (ecx & CPUID_F1_ECX_RDRAND)) {
+ LogPrintf("Using RdRand as an additional entropy source\n");
+ rdrand_supported = true;
+ }
+ hwrand_initialized.store(true);
+}
+#else
+static void RDRandInit() {}
+#endif
+
+static bool GetHWRand(unsigned char* ent32) {
+#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
+ assert(hwrand_initialized.load(std::memory_order_relaxed));
+ if (rdrand_supported) {
+ uint8_t ok;
+ // Not all assemblers support the rdrand instruction, write it in hex.
+#ifdef __i386__
+ for (int iter = 0; iter < 4; ++iter) {
+ uint32_t r1, r2;
+ __asm__ volatile (".byte 0x0f, 0xc7, 0xf0;" // rdrand %eax
+ ".byte 0x0f, 0xc7, 0xf2;" // rdrand %edx
+ "setc %2" :
+ "=a"(r1), "=d"(r2), "=q"(ok) :: "cc");
+ if (!ok) return false;
+ WriteLE32(ent32 + 8 * iter, r1);
+ WriteLE32(ent32 + 8 * iter + 4, r2);
+ }
+#else
+ uint64_t r1, r2, r3, r4;
+ __asm__ volatile (".byte 0x48, 0x0f, 0xc7, 0xf0, " // rdrand %rax
+ "0x48, 0x0f, 0xc7, 0xf3, " // rdrand %rbx
+ "0x48, 0x0f, 0xc7, 0xf1, " // rdrand %rcx
+ "0x48, 0x0f, 0xc7, 0xf2; " // rdrand %rdx
+ "setc %4" :
+ "=a"(r1), "=b"(r2), "=c"(r3), "=d"(r4), "=q"(ok) :: "cc");
+ if (!ok) return false;
+ WriteLE64(ent32, r1);
+ WriteLE64(ent32 + 8, r2);
+ WriteLE64(ent32 + 16, r3);
+ WriteLE64(ent32 + 24, r4);
+#endif
+ return true;
+ }
+#endif
+ return false;
}
void RandAddSeed()
@@ -71,7 +155,7 @@ static void RandAddSeedPerfmon()
const size_t nMaxSize = 10000000; // Bail out at more than 10MB of performance data
while (true) {
nSize = vData.size();
- ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, vData.data(), &nSize);
+ ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "Global", nullptr, nullptr, vData.data(), &nSize);
if (ret != ERROR_MORE_DATA || vData.size() >= nMaxSize)
break;
vData.resize(std::max((vData.size() * 3) / 2, nMaxSize)); // Grow size of buffer exponentially
@@ -80,7 +164,7 @@ static void RandAddSeedPerfmon()
if (ret == ERROR_SUCCESS) {
RAND_add(vData.data(), nSize, nSize / 100.0);
memory_cleanse(vData.data(), nSize);
- LogPrint("rand", "%s: %lu bytes\n", __func__, nSize);
+ LogPrint(BCLog::RAND, "%s: %lu bytes\n", __func__, nSize);
} else {
static bool warned = false; // Warn only once
if (!warned) {
@@ -91,34 +175,98 @@ static void RandAddSeedPerfmon()
#endif
}
+#ifndef WIN32
+/** Fallback: get 32 bytes of system entropy from /dev/urandom. The most
+ * compatible way to get cryptographic randomness on UNIX-ish platforms.
+ */
+void GetDevURandom(unsigned char *ent32)
+{
+ int f = open("/dev/urandom", O_RDONLY);
+ if (f == -1) {
+ RandFailure();
+ }
+ int have = 0;
+ do {
+ ssize_t n = read(f, ent32 + have, NUM_OS_RANDOM_BYTES - have);
+ if (n <= 0 || n + have > NUM_OS_RANDOM_BYTES) {
+ close(f);
+ RandFailure();
+ }
+ have += n;
+ } while (have < NUM_OS_RANDOM_BYTES);
+ close(f);
+}
+#endif
+
/** Get 32 bytes of system entropy. */
-static void GetOSRand(unsigned char *ent32)
+void GetOSRand(unsigned char *ent32)
{
-#ifdef WIN32
+#if defined(WIN32)
HCRYPTPROV hProvider;
- int ret = CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
+ int ret = CryptAcquireContextW(&hProvider, nullptr, nullptr, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
if (!ret) {
RandFailure();
}
- ret = CryptGenRandom(hProvider, 32, ent32);
+ ret = CryptGenRandom(hProvider, NUM_OS_RANDOM_BYTES, ent32);
if (!ret) {
RandFailure();
}
CryptReleaseContext(hProvider, 0);
-#else
- int f = open("/dev/urandom", O_RDONLY);
- if (f == -1) {
+#elif defined(HAVE_SYS_GETRANDOM)
+ /* Linux. From the getrandom(2) man page:
+ * "If the urandom source has been initialized, reads of up to 256 bytes
+ * will always return as many bytes as requested and will not be
+ * interrupted by signals."
+ */
+ int rv = syscall(SYS_getrandom, ent32, NUM_OS_RANDOM_BYTES, 0);
+ if (rv != NUM_OS_RANDOM_BYTES) {
+ if (rv < 0 && errno == ENOSYS) {
+ /* Fallback for kernel <3.17: the return value will be -1 and errno
+ * ENOSYS if the syscall is not available, in that case fall back
+ * to /dev/urandom.
+ */
+ GetDevURandom(ent32);
+ } else {
+ RandFailure();
+ }
+ }
+#elif defined(HAVE_GETENTROPY) && defined(__OpenBSD__)
+ /* On OpenBSD this can return up to 256 bytes of entropy, will return an
+ * error if more are requested.
+ * The call cannot return less than the requested number of bytes.
+ getentropy is explicitly limited to openbsd here, as a similar (but not
+ the same) function may exist on other platforms via glibc.
+ */
+ if (getentropy(ent32, NUM_OS_RANDOM_BYTES) != 0) {
RandFailure();
}
+#elif defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX)
+ // We need a fallback for OSX < 10.12
+ if (&getentropy != nullptr) {
+ if (getentropy(ent32, NUM_OS_RANDOM_BYTES) != 0) {
+ RandFailure();
+ }
+ } else {
+ GetDevURandom(ent32);
+ }
+#elif defined(HAVE_SYSCTL_ARND)
+ /* FreeBSD and similar. It is possible for the call to return less
+ * bytes than requested, so need to read in a loop.
+ */
+ static const int name[2] = {CTL_KERN, KERN_ARND};
int have = 0;
do {
- ssize_t n = read(f, ent32 + have, 32 - have);
- if (n <= 0 || n + have > 32) {
+ size_t len = NUM_OS_RANDOM_BYTES - have;
+ if (sysctl(name, ARRAYLEN(name), ent32 + have, &len, nullptr, 0) != 0) {
RandFailure();
}
- have += n;
- } while (have < 32);
- close(f);
+ have += len;
+ } while (have < NUM_OS_RANDOM_BYTES);
+#else
+ /* Fall back to /dev/urandom if there is no specific method implemented to
+ * get system entropy for this OS.
+ */
+ GetDevURandom(ent32);
#endif
}
@@ -129,6 +277,43 @@ void GetRandBytes(unsigned char* buf, int num)
}
}
+static void AddDataToRng(void* data, size_t len);
+
+void RandAddSeedSleep()
+{
+ int64_t nPerfCounter1 = GetPerformanceCounter();
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ int64_t nPerfCounter2 = GetPerformanceCounter();
+
+ // Combine with and update state
+ AddDataToRng(&nPerfCounter1, sizeof(nPerfCounter1));
+ AddDataToRng(&nPerfCounter2, sizeof(nPerfCounter2));
+
+ memory_cleanse(&nPerfCounter1, sizeof(nPerfCounter1));
+ memory_cleanse(&nPerfCounter2, sizeof(nPerfCounter2));
+}
+
+
+static std::mutex cs_rng_state;
+static unsigned char rng_state[32] = {0};
+static uint64_t rng_counter = 0;
+
+static void AddDataToRng(void* data, size_t len) {
+ CSHA512 hasher;
+ hasher.Write((const unsigned char*)&len, sizeof(len));
+ hasher.Write((const unsigned char*)data, len);
+ unsigned char buf[64];
+ {
+ std::unique_lock<std::mutex> lock(cs_rng_state);
+ hasher.Write(rng_state, sizeof(rng_state));
+ hasher.Write((const unsigned char*)&rng_counter, sizeof(rng_counter));
+ ++rng_counter;
+ hasher.Finalize(buf);
+ memcpy(rng_state, buf + 32, 32);
+ }
+ memory_cleanse(buf, 64);
+}
+
void GetStrongRandBytes(unsigned char* out, int num)
{
assert(num <= 32);
@@ -144,8 +329,22 @@ void GetStrongRandBytes(unsigned char* out, int num)
GetOSRand(buf);
hasher.Write(buf, 32);
+ // Third source: HW RNG, if available.
+ if (GetHWRand(buf)) {
+ hasher.Write(buf, 32);
+ }
+
+ // Combine with and update state
+ {
+ std::unique_lock<std::mutex> lock(cs_rng_state);
+ hasher.Write(rng_state, sizeof(rng_state));
+ hasher.Write((const unsigned char*)&rng_counter, sizeof(rng_counter));
+ ++rng_counter;
+ hasher.Finalize(buf);
+ memcpy(rng_state, buf + 32, 32);
+ }
+
// Produce output
- hasher.Finalize(buf);
memcpy(out, buf, num);
memory_cleanse(buf, 64);
}
@@ -177,21 +376,92 @@ uint256 GetRandHash()
return hash;
}
-FastRandomContext::FastRandomContext(bool fDeterministic)
+void FastRandomContext::RandomSeed()
{
- // The seed values have some unlikely fixed points which we avoid.
- if (fDeterministic) {
- Rz = Rw = 11;
- } else {
- uint32_t tmp;
- do {
- GetRandBytes((unsigned char*)&tmp, 4);
- } while (tmp == 0 || tmp == 0x9068ffffU);
- Rz = tmp;
- do {
- GetRandBytes((unsigned char*)&tmp, 4);
- } while (tmp == 0 || tmp == 0x464fffffU);
- Rw = tmp;
+ uint256 seed = GetRandHash();
+ rng.SetKey(seed.begin(), 32);
+ requires_seed = false;
+}
+
+uint256 FastRandomContext::rand256()
+{
+ if (bytebuf_size < 32) {
+ FillByteBuffer();
+ }
+ uint256 ret;
+ memcpy(ret.begin(), bytebuf + 64 - bytebuf_size, 32);
+ bytebuf_size -= 32;
+ return ret;
+}
+
+std::vector<unsigned char> FastRandomContext::randbytes(size_t len)
+{
+ std::vector<unsigned char> ret(len);
+ if (len > 0) {
+ rng.Output(&ret[0], len);
}
+ return ret;
}
+FastRandomContext::FastRandomContext(const uint256& seed) : requires_seed(false), bytebuf_size(0), bitbuf_size(0)
+{
+ rng.SetKey(seed.begin(), 32);
+}
+
+bool Random_SanityCheck()
+{
+ uint64_t start = GetPerformanceCounter();
+
+ /* This does not measure the quality of randomness, but it does test that
+ * OSRandom() overwrites all 32 bytes of the output given a maximum
+ * number of tries.
+ */
+ static const ssize_t MAX_TRIES = 1024;
+ uint8_t data[NUM_OS_RANDOM_BYTES];
+ bool overwritten[NUM_OS_RANDOM_BYTES] = {}; /* Tracks which bytes have been overwritten at least once */
+ int num_overwritten;
+ int tries = 0;
+ /* Loop until all bytes have been overwritten at least once, or max number tries reached */
+ do {
+ memset(data, 0, NUM_OS_RANDOM_BYTES);
+ GetOSRand(data);
+ for (int x=0; x < NUM_OS_RANDOM_BYTES; ++x) {
+ overwritten[x] |= (data[x] != 0);
+ }
+
+ num_overwritten = 0;
+ for (int x=0; x < NUM_OS_RANDOM_BYTES; ++x) {
+ if (overwritten[x]) {
+ num_overwritten += 1;
+ }
+ }
+
+ tries += 1;
+ } while (num_overwritten < NUM_OS_RANDOM_BYTES && tries < MAX_TRIES);
+ if (num_overwritten != NUM_OS_RANDOM_BYTES) return false; /* If this failed, bailed out after too many tries */
+
+ // Check that GetPerformanceCounter increases at least during a GetOSRand() call + 1ms sleep.
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ uint64_t stop = GetPerformanceCounter();
+ if (stop == start) return false;
+
+ // We called GetPerformanceCounter. Use it as entropy.
+ RAND_add((const unsigned char*)&start, sizeof(start), 1);
+ RAND_add((const unsigned char*)&stop, sizeof(stop), 1);
+
+ return true;
+}
+
+FastRandomContext::FastRandomContext(bool fDeterministic) : requires_seed(!fDeterministic), bytebuf_size(0), bitbuf_size(0)
+{
+ if (!fDeterministic) {
+ return;
+ }
+ uint256 seed;
+ rng.SetKey(seed.begin(), 32);
+}
+
+void RandomInit()
+{
+ RDRandInit();
+}
diff --git a/src/random.h b/src/random.h
index 664f030eba..c60ab36179 100644
--- a/src/random.h
+++ b/src/random.h
@@ -6,6 +6,8 @@
#ifndef BITCOIN_RANDOM_H
#define BITCOIN_RANDOM_H
+#include "crypto/chacha20.h"
+#include "crypto/common.h"
#include "uint256.h"
#include <stdint.h>
@@ -22,6 +24,13 @@ int GetRandInt(int nMax);
uint256 GetRandHash();
/**
+ * Add a little bit of randomness to the output of GetStrongRangBytes.
+ * This sleeps for a millisecond, so should only be called when there is
+ * no other work to be done.
+ */
+void RandAddSeedSleep();
+
+/**
* Function to gather random data from multiple sources, failing whenever any
* of those source fail to provide a result.
*/
@@ -33,17 +42,105 @@ void GetStrongRandBytes(unsigned char* buf, int num);
* This class is not thread-safe.
*/
class FastRandomContext {
+private:
+ bool requires_seed;
+ ChaCha20 rng;
+
+ unsigned char bytebuf[64];
+ int bytebuf_size;
+
+ uint64_t bitbuf;
+ int bitbuf_size;
+
+ void RandomSeed();
+
+ void FillByteBuffer()
+ {
+ if (requires_seed) {
+ RandomSeed();
+ }
+ rng.Output(bytebuf, sizeof(bytebuf));
+ bytebuf_size = sizeof(bytebuf);
+ }
+
+ void FillBitBuffer()
+ {
+ bitbuf = rand64();
+ bitbuf_size = 64;
+ }
+
public:
- explicit FastRandomContext(bool fDeterministic=false);
+ explicit FastRandomContext(bool fDeterministic = false);
+
+ /** Initialize with explicit seed (only for testing) */
+ explicit FastRandomContext(const uint256& seed);
+
+ /** Generate a random 64-bit integer. */
+ uint64_t rand64()
+ {
+ if (bytebuf_size < 8) FillByteBuffer();
+ uint64_t ret = ReadLE64(bytebuf + 64 - bytebuf_size);
+ bytebuf_size -= 8;
+ return ret;
+ }
+
+ /** Generate a random (bits)-bit integer. */
+ uint64_t randbits(int bits) {
+ if (bits == 0) {
+ return 0;
+ } else if (bits > 32) {
+ return rand64() >> (64 - bits);
+ } else {
+ if (bitbuf_size < bits) FillBitBuffer();
+ uint64_t ret = bitbuf & (~(uint64_t)0 >> (64 - bits));
+ bitbuf >>= bits;
+ bitbuf_size -= bits;
+ return ret;
+ }
+ }
- uint32_t rand32() {
- Rz = 36969 * (Rz & 65535) + (Rz >> 16);
- Rw = 18000 * (Rw & 65535) + (Rw >> 16);
- return (Rw << 16) + Rz;
+ /** Generate a random integer in the range [0..range). */
+ uint64_t randrange(uint64_t range)
+ {
+ --range;
+ int bits = CountBits(range);
+ while (true) {
+ uint64_t ret = randbits(bits);
+ if (ret <= range) return ret;
+ }
}
- uint32_t Rz;
- uint32_t Rw;
+ /** Generate random bytes. */
+ std::vector<unsigned char> randbytes(size_t len);
+
+ /** Generate a random 32-bit integer. */
+ uint32_t rand32() { return randbits(32); }
+
+ /** generate a random uint256. */
+ uint256 rand256();
+
+ /** Generate a random boolean. */
+ bool randbool() { return randbits(1); }
};
+/* Number of random bytes returned by GetOSRand.
+ * When changing this constant make sure to change all call sites, and make
+ * sure that the underlying OS APIs for all platforms support the number.
+ * (many cap out at 256 bytes).
+ */
+static const ssize_t NUM_OS_RANDOM_BYTES = 32;
+
+/** Get 32 bytes of system entropy. Do not use this in application code: use
+ * GetStrongRandBytes instead.
+ */
+void GetOSRand(unsigned char *ent32);
+
+/** Check that OS randomness is available and returning the requested number
+ * of bytes.
+ */
+bool Random_SanityCheck();
+
+/** Initialize the RNG. */
+void RandomInit();
+
#endif // BITCOIN_RANDOM_H
diff --git a/src/rest.cpp b/src/rest.cpp
index 8a7c985e72..0b2c843d5f 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -5,10 +5,12 @@
#include "chain.h"
#include "chainparams.h"
+#include "core_io.h"
#include "primitives/block.h"
#include "primitives/transaction.h"
#include "validation.h"
#include "httpserver.h"
+#include "rpc/blockchain.h"
#include "rpc/server.h"
#include "streams.h"
#include "sync.h"
@@ -17,12 +19,9 @@
#include "version.h"
#include <boost/algorithm/string.hpp>
-#include <boost/dynamic_bitset.hpp>
#include <univalue.h>
-using namespace std;
-
static const size_t MAX_GETUTXOS_OUTPOINTS = 15; //allow a max of 15 outpoints to be queried at once
enum RetFormat {
@@ -43,29 +42,25 @@ static const struct {
};
struct CCoin {
- uint32_t nTxVer; // Don't call this nVersion, that name has a special meaning inside IMPLEMENT_SERIALIZE
uint32_t nHeight;
CTxOut out;
ADD_SERIALIZE_METHODS;
+ CCoin() : nHeight(0) {}
+ explicit CCoin(Coin&& in) : nHeight(in.nHeight), out(std::move(in.out)) {}
+
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
{
- READWRITE(nTxVer);
+ uint32_t nTxVerDummy = 0;
+ READWRITE(nTxVerDummy);
READWRITE(nHeight);
READWRITE(out);
}
};
-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 bool RESTERR(HTTPRequest* req, enum HTTPStatusCode status, string message)
+static bool RESTERR(HTTPRequest* req, enum HTTPStatusCode status, std::string message)
{
req->WriteHeader("Content-Type", "text/plain");
req->WriteReply(status, message + "\r\n");
@@ -93,9 +88,9 @@ static enum RetFormat ParseDataFormat(std::string& param, const std::string& str
return rf_names[0].rf;
}
-static string AvailableDataFormatsString()
+static std::string AvailableDataFormatsString()
{
- string formats = "";
+ std::string formats = "";
for (unsigned int i = 0; i < ARRAYLEN(rf_names); i++)
if (strlen(rf_names[i].name) > 0) {
formats.append(".");
@@ -109,7 +104,7 @@ static string AvailableDataFormatsString()
return formats;
}
-static bool ParseHashStr(const string& strReq, uint256& v)
+static bool ParseHashStr(const std::string& strReq, uint256& v)
{
if (!IsHex(strReq) || (strReq.size() != 64))
return false;
@@ -133,17 +128,17 @@ static bool rest_headers(HTTPRequest* req,
return false;
std::string param;
const RetFormat rf = ParseDataFormat(param, strURIPart);
- vector<string> path;
+ std::vector<std::string> path;
boost::split(path, param, boost::is_any_of("/"));
if (path.size() != 2)
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);
+ long count = strtol(path[0].c_str(), nullptr, 10);
if (count < 1 || count > 2000)
return RESTERR(req, HTTP_BAD_REQUEST, "Header count out of range: " + path[0]);
- string hashStr = path[1];
+ std::string hashStr = path[1];
uint256 hash;
if (!ParseHashStr(hashStr, hash))
return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
@@ -153,8 +148,8 @@ static bool rest_headers(HTTPRequest* req,
{
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)) {
+ const CBlockIndex *pindex = (it != mapBlockIndex.end()) ? it->second : nullptr;
+ while (pindex != nullptr && chainActive.Contains(pindex)) {
headers.push_back(pindex);
if (headers.size() == (unsigned long)count)
break;
@@ -163,30 +158,30 @@ static bool rest_headers(HTTPRequest* req,
}
CDataStream ssHeader(SER_NETWORK, PROTOCOL_VERSION);
- BOOST_FOREACH(const CBlockIndex *pindex, headers) {
+ for (const CBlockIndex *pindex : headers) {
ssHeader << pindex->GetBlockHeader();
}
switch (rf) {
case RF_BINARY: {
- string binaryHeader = ssHeader.str();
+ std::string binaryHeader = ssHeader.str();
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";
+ std::string strHex = HexStr(ssHeader.begin(), ssHeader.end()) + "\n";
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) {
+ for (const CBlockIndex *pindex : headers) {
jsonHeaders.push_back(blockheaderToJSON(pindex));
}
- string strJSON = jsonHeaders.write() + "\n";
+ std::string strJSON = jsonHeaders.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
req->WriteReply(HTTP_OK, strJSON);
return true;
@@ -195,9 +190,6 @@ static bool rest_headers(HTTPRequest* req,
return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: .bin, .hex)");
}
}
-
- // not reached
- return true; // continue to process further HTTP reqs on this cxn
}
static bool rest_block(HTTPRequest* req,
@@ -214,7 +206,7 @@ static bool rest_block(HTTPRequest* req,
return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
CBlock block;
- CBlockIndex* pblockindex = NULL;
+ CBlockIndex* pblockindex = nullptr;
{
LOCK(cs_main);
if (mapBlockIndex.count(hash) == 0)
@@ -233,14 +225,14 @@ static bool rest_block(HTTPRequest* req,
switch (rf) {
case RF_BINARY: {
- string binaryBlock = ssBlock.str();
+ std::string binaryBlock = ssBlock.str();
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";
+ std::string strHex = HexStr(ssBlock.begin(), ssBlock.end()) + "\n";
req->WriteHeader("Content-Type", "text/plain");
req->WriteReply(HTTP_OK, strHex);
return true;
@@ -248,7 +240,7 @@ static bool rest_block(HTTPRequest* req,
case RF_JSON: {
UniValue objBlock = blockToJSON(block, pblockindex, showTxDetails);
- string strJSON = objBlock.write() + "\n";
+ std::string strJSON = objBlock.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
req->WriteReply(HTTP_OK, strJSON);
return true;
@@ -258,9 +250,6 @@ static bool rest_block(HTTPRequest* req,
return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
}
}
-
- // not reached
- return true; // continue to process further HTTP reqs on this cxn
}
static bool rest_block_extended(HTTPRequest* req, const std::string& strURIPart)
@@ -288,7 +277,7 @@ static bool rest_chaininfo(HTTPRequest* req, const std::string& strURIPart)
JSONRPCRequest jsonRequest;
jsonRequest.params = UniValue(UniValue::VARR);
UniValue chainInfoObject = getblockchaininfo(jsonRequest);
- string strJSON = chainInfoObject.write() + "\n";
+ std::string strJSON = chainInfoObject.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
req->WriteReply(HTTP_OK, strJSON);
return true;
@@ -297,9 +286,6 @@ static bool rest_chaininfo(HTTPRequest* req, const std::string& strURIPart)
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_mempool_info(HTTPRequest* req, const std::string& strURIPart)
@@ -313,7 +299,7 @@ static bool rest_mempool_info(HTTPRequest* req, const std::string& strURIPart)
case RF_JSON: {
UniValue mempoolInfoObject = mempoolInfoToJSON();
- string strJSON = mempoolInfoObject.write() + "\n";
+ std::string strJSON = mempoolInfoObject.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
req->WriteReply(HTTP_OK, strJSON);
return true;
@@ -322,9 +308,6 @@ static bool rest_mempool_info(HTTPRequest* req, const std::string& strURIPart)
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_mempool_contents(HTTPRequest* req, const std::string& strURIPart)
@@ -338,7 +321,7 @@ static bool rest_mempool_contents(HTTPRequest* req, const std::string& strURIPar
case RF_JSON: {
UniValue mempoolObject = mempoolToJSON(true);
- string strJSON = mempoolObject.write() + "\n";
+ std::string strJSON = mempoolObject.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
req->WriteReply(HTTP_OK, strJSON);
return true;
@@ -347,9 +330,6 @@ static bool rest_mempool_contents(HTTPRequest* req, const std::string& strURIPar
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)
@@ -373,14 +353,14 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart)
switch (rf) {
case RF_BINARY: {
- string binaryTx = ssTx.str();
+ std::string binaryTx = ssTx.str();
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";
+ std::string strHex = HexStr(ssTx.begin(), ssTx.end()) + "\n";
req->WriteHeader("Content-Type", "text/plain");
req->WriteReply(HTTP_OK, strHex);
return true;
@@ -388,8 +368,8 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart)
case RF_JSON: {
UniValue objTx(UniValue::VOBJ);
- TxToJSON(*tx, hashBlock, objTx);
- string strJSON = objTx.write() + "\n";
+ TxToUniv(*tx, hashBlock, objTx);
+ std::string strJSON = objTx.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
req->WriteReply(HTTP_OK, strJSON);
return true;
@@ -399,9 +379,6 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart)
return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
}
}
-
- // not reached
- return true; // continue to process further HTTP reqs on this cxn
}
static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
@@ -411,21 +388,21 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
std::string param;
const RetFormat rf = ParseDataFormat(param, strURIPart);
- vector<string> uriParts;
+ std::vector<std::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
+ // throw exception in case of an empty request
std::string strRequestMutable = req->ReadBody();
if (strRequestMutable.length() == 0 && uriParts.size() == 0)
return RESTERR(req, HTTP_BAD_REQUEST, "Error: empty request");
bool fInputParsed = false;
bool fCheckMemPool = false;
- vector<COutPoint> vOutPoints;
+ std::vector<COutPoint> vOutPoints;
// parse/deserialize input
// input-format = output-format, rest/getutxos/bin requires binary input, gives binary output, ...
@@ -499,10 +476,11 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
return RESTERR(req, HTTP_BAD_REQUEST, 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-readable string representation)
- vector<unsigned char> bitmap;
- vector<CCoin> outs;
+ std::vector<unsigned char> bitmap;
+ std::vector<CCoin> outs;
std::string bitmapStringRepresentation;
- boost::dynamic_bitset<unsigned char> hits(vOutPoints.size());
+ std::vector<bool> hits;
+ bitmap.resize((vOutPoints.size() + 7) / 8);
{
LOCK2(cs_main, mempool.cs);
@@ -516,27 +494,18 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
view.SetBackend(viewMempool); // switch cache backend to db+mempool in case user likes to query mempool
for (size_t i = 0; i < vOutPoints.size(); i++) {
- CCoins coins;
- uint256 hash = vOutPoints[i].hash;
- if (view.GetCoins(hash, coins)) {
- mempool.pruneSpent(hash, coins);
- if (coins.IsAvailable(vOutPoints[i].n)) {
- hits[i] = true;
- // Safe to index into vout here because IsAvailable checked if it's off the end of the array, or if
- // n is valid but points to an already spent output (IsNull).
- CCoin coin;
- coin.nTxVer = coins.nVersion;
- coin.nHeight = coins.nHeight;
- coin.out = coins.vout.at(vOutPoints[i].n);
- assert(!coin.out.IsNull());
- outs.push_back(coin);
- }
+ bool hit = false;
+ Coin coin;
+ if (view.GetCoin(vOutPoints[i], coin) && !mempool.isSpent(vOutPoints[i])) {
+ hit = true;
+ outs.emplace_back(std::move(coin));
}
- bitmapStringRepresentation.append(hits[i] ? "1" : "0"); // form a binary string representation (human-readable for json output)
+ hits.push_back(hit);
+ bitmapStringRepresentation.append(hit ? "1" : "0"); // form a binary string representation (human-readable for json output)
+ bitmap[i / 8] |= ((uint8_t)hit) << (i % 8);
}
}
- boost::to_block_range(hits, std::back_inserter(bitmap));
switch (rf) {
case RF_BINARY: {
@@ -544,7 +513,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
// use exact same output as mentioned in Bip64
CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION);
ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash() << bitmap << outs;
- string ssGetUTXOResponseString = ssGetUTXOResponse.str();
+ std::string ssGetUTXOResponseString = ssGetUTXOResponse.str();
req->WriteHeader("Content-Type", "application/octet-stream");
req->WriteReply(HTTP_OK, ssGetUTXOResponseString);
@@ -554,7 +523,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
case RF_HEX: {
CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION);
ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash() << bitmap << outs;
- string strHex = HexStr(ssGetUTXOResponse.begin(), ssGetUTXOResponse.end()) + "\n";
+ std::string strHex = HexStr(ssGetUTXOResponse.begin(), ssGetUTXOResponse.end()) + "\n";
req->WriteHeader("Content-Type", "text/plain");
req->WriteReply(HTTP_OK, strHex);
@@ -571,22 +540,21 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
objGetUTXOResponse.push_back(Pair("bitmap", bitmapStringRepresentation));
UniValue utxos(UniValue::VARR);
- BOOST_FOREACH (const CCoin& coin, outs) {
+ for (const CCoin& coin : outs) {
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
UniValue o(UniValue::VOBJ);
- ScriptPubKeyToJSON(coin.out.scriptPubKey, o, true);
+ ScriptPubKeyToUniv(coin.out.scriptPubKey, o, true);
utxo.push_back(Pair("scriptPubKey", o));
utxos.push_back(utxo);
}
objGetUTXOResponse.push_back(Pair("utxos", utxos));
// return json string
- string strJSON = objGetUTXOResponse.write() + "\n";
+ std::string strJSON = objGetUTXOResponse.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
req->WriteReply(HTTP_OK, strJSON);
return true;
@@ -595,9 +563,6 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
}
}
-
- // not reached
- return true; // continue to process further HTTP reqs on this cxn
}
static const struct {
diff --git a/src/reverse_iterator.h b/src/reverse_iterator.h
new file mode 100644
index 0000000000..ab467f07c9
--- /dev/null
+++ b/src/reverse_iterator.h
@@ -0,0 +1,39 @@
+// Taken from https://gist.github.com/arvidsson/7231973
+
+#ifndef BITCOIN_REVERSE_ITERATOR_H
+#define BITCOIN_REVERSE_ITERATOR_H
+
+/**
+ * Template used for reverse iteration in C++11 range-based for loops.
+ *
+ * std::vector<int> v = {1, 2, 3, 4, 5};
+ * for (auto x : reverse_iterate(v))
+ * std::cout << x << " ";
+ */
+
+template <typename T>
+class reverse_range
+{
+ T &m_x;
+
+public:
+ explicit reverse_range(T &x) : m_x(x) {}
+
+ auto begin() const -> decltype(this->m_x.rbegin())
+ {
+ return m_x.rbegin();
+ }
+
+ auto end() const -> decltype(this->m_x.rend())
+ {
+ return m_x.rend();
+ }
+};
+
+template <typename T>
+reverse_range<T> reverse_iterate(T &x)
+{
+ return reverse_range<T>(x);
+}
+
+#endif // BITCOIN_REVERSE_ITERATOR_H
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 368654bfa6..19074d3d95 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -3,6 +3,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "rpc/blockchain.h"
+
#include "amount.h"
#include "chain.h"
#include "chainparams.h"
@@ -10,15 +12,19 @@
#include "coins.h"
#include "consensus/validation.h"
#include "validation.h"
+#include "core_io.h"
+#include "policy/feerate.h"
#include "policy/policy.h"
#include "primitives/transaction.h"
#include "rpc/server.h"
#include "streams.h"
#include "sync.h"
+#include "txdb.h"
#include "txmempool.h"
#include "util.h"
#include "utilstrencodings.h"
#include "hash.h"
+#include "warnings.h"
#include <stdint.h>
@@ -28,7 +34,6 @@
#include <mutex>
#include <condition_variable>
-using namespace std;
struct CUpdatedBlock
{
@@ -41,15 +46,12 @@ static std::condition_variable cond_blockchange;
static CUpdatedBlock latestblock;
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)
{
- // Floating point number that is a multiple of the minimum difficulty,
- // minimum difficulty = 1.0.
- if (blockindex == NULL)
+ if (blockindex == nullptr)
{
- if (chainActive.Tip() == NULL)
+ if (chainActive.Tip() == nullptr)
return 1.0;
else
blockindex = chainActive.Tip();
@@ -102,7 +104,7 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex)
return result;
}
-UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false)
+UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails)
{
UniValue result(UniValue::VOBJ);
result.push_back(Pair("hash", blockindex->GetBlockHash().GetHex()));
@@ -124,7 +126,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
if(txDetails)
{
UniValue objTx(UniValue::VOBJ);
- TxToJSON(*tx, uint256(), objTx);
+ TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags());
txs.push_back(objTx);
}
else
@@ -149,7 +151,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
UniValue getblockcount(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getblockcount\n"
"\nReturns the number of blocks in the longest blockchain.\n"
"\nResult:\n"
@@ -166,7 +168,7 @@ UniValue getblockcount(const JSONRPCRequest& request)
UniValue getbestblockhash(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getbestblockhash\n"
"\nReturns the hash of the best (tip) block in the longest blockchain.\n"
"\nResult:\n"
@@ -187,13 +189,13 @@ void RPCNotifyBlockChange(bool ibd, const CBlockIndex * pindex)
latestblock.hash = pindex->GetBlockHash();
latestblock.height = pindex->nHeight;
}
- cond_blockchange.notify_all();
+ cond_blockchange.notify_all();
}
UniValue waitfornewblock(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 1)
- throw runtime_error(
+ throw std::runtime_error(
"waitfornewblock (timeout)\n"
"\nWaits for a specific new block and returns useful info about it.\n"
"\nReturns the current block on timeout or exit.\n"
@@ -209,7 +211,7 @@ UniValue waitfornewblock(const JSONRPCRequest& request)
+ HelpExampleRpc("waitfornewblock", "1000")
);
int timeout = 0;
- if (request.params.size() > 0)
+ if (!request.params[0].isNull())
timeout = request.params[0].get_int();
CUpdatedBlock block;
@@ -231,7 +233,7 @@ UniValue waitfornewblock(const JSONRPCRequest& request)
UniValue waitforblock(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"waitforblock <blockhash> (timeout)\n"
"\nWaits for a specific new block and returns useful info about it.\n"
"\nReturns the current block on timeout or exit.\n"
@@ -251,7 +253,7 @@ UniValue waitforblock(const JSONRPCRequest& request)
uint256 hash = uint256S(request.params[0].get_str());
- if (request.params.size() > 1)
+ if (!request.params[1].isNull())
timeout = request.params[1].get_int();
CUpdatedBlock block;
@@ -273,7 +275,7 @@ UniValue waitforblock(const JSONRPCRequest& request)
UniValue waitforblockheight(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"waitforblockheight <height> (timeout)\n"
"\nWaits for (at least) block height and returns the height and hash\n"
"of the current tip.\n"
@@ -294,7 +296,7 @@ UniValue waitforblockheight(const JSONRPCRequest& request)
int height = request.params[0].get_int();
- if (request.params.size() > 1)
+ if (!request.params[1].isNull())
timeout = request.params[1].get_int();
CUpdatedBlock block;
@@ -315,7 +317,7 @@ UniValue waitforblockheight(const JSONRPCRequest& request)
UniValue getdifficulty(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getdifficulty\n"
"\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n"
"\nResult:\n"
@@ -336,14 +338,13 @@ std::string EntryDescriptionString()
" \"modifiedfee\" : n, (numeric) transaction fee with fee deltas used for mining priority\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) DEPRECATED. Priority when transaction entered pool\n"
- " \"currentpriority\" : n, (numeric) DEPRECATED. Transaction priority now\n"
" \"descendantcount\" : n, (numeric) number of in-mempool descendant transactions (including this one)\n"
" \"descendantsize\" : n, (numeric) virtual transaction size of in-mempool descendants (including this one)\n"
" \"descendantfees\" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one)\n"
" \"ancestorcount\" : n, (numeric) number of in-mempool ancestor transactions (including this one)\n"
" \"ancestorsize\" : n, (numeric) virtual transaction size of in-mempool ancestors (including this one)\n"
" \"ancestorfees\" : n, (numeric) modified fees (see above) of in-mempool ancestors (including this one)\n"
+ " \"wtxid\" : hash, (string) hash of serialized transaction, including witness data\n"
" \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n"
" \"transactionid\", (string) parent transaction id\n"
" ... ]\n";
@@ -358,24 +359,23 @@ void entryToJSON(UniValue &info, const CTxMemPoolEntry &e)
info.push_back(Pair("modifiedfee", ValueFromAmount(e.GetModifiedFee())));
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.GetModFeesWithDescendants()));
info.push_back(Pair("ancestorcount", e.GetCountWithAncestors()));
info.push_back(Pair("ancestorsize", e.GetSizeWithAncestors()));
info.push_back(Pair("ancestorfees", e.GetModFeesWithAncestors()));
+ info.push_back(Pair("wtxid", mempool.vTxHashes[e.vTxHashesIdx].first.ToString()));
const CTransaction& tx = e.GetTx();
- set<string> setDepends;
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ std::set<std::string> setDepends;
+ for (const CTxIn& txin : tx.vin)
{
if (mempool.exists(txin.prevout.hash))
setDepends.insert(txin.prevout.hash.ToString());
}
UniValue depends(UniValue::VARR);
- BOOST_FOREACH(const string& dep, setDepends)
+ for (const std::string& dep : setDepends)
{
depends.push_back(dep);
}
@@ -383,13 +383,13 @@ void entryToJSON(UniValue &info, const CTxMemPoolEntry &e)
info.push_back(Pair("depends", depends));
}
-UniValue mempoolToJSON(bool fVerbose = false)
+UniValue mempoolToJSON(bool fVerbose)
{
if (fVerbose)
{
LOCK(mempool.cs);
UniValue o(UniValue::VOBJ);
- BOOST_FOREACH(const CTxMemPoolEntry& e, mempool.mapTx)
+ for (const CTxMemPoolEntry& e : mempool.mapTx)
{
const uint256& hash = e.GetTx().GetHash();
UniValue info(UniValue::VOBJ);
@@ -400,11 +400,11 @@ UniValue mempoolToJSON(bool fVerbose = false)
}
else
{
- vector<uint256> vtxid;
+ std::vector<uint256> vtxid;
mempool.queryHashes(vtxid);
UniValue a(UniValue::VARR);
- BOOST_FOREACH(const uint256& hash, vtxid)
+ for (const uint256& hash : vtxid)
a.push_back(hash.ToString());
return a;
@@ -414,9 +414,10 @@ UniValue mempoolToJSON(bool fVerbose = false)
UniValue getrawmempool(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 1)
- throw runtime_error(
+ throw std::runtime_error(
"getrawmempool ( verbose )\n"
"\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n"
+ "\nHint: use getmempoolentry to fetch a specific transaction from the mempool.\n"
"\nArguments:\n"
"1. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids\n"
"\nResult: (for verbose = false):\n"
@@ -436,7 +437,7 @@ UniValue getrawmempool(const JSONRPCRequest& request)
);
bool fVerbose = false;
- if (request.params.size() > 0)
+ if (!request.params[0].isNull())
fVerbose = request.params[0].get_bool();
return mempoolToJSON(fVerbose);
@@ -445,7 +446,7 @@ UniValue getrawmempool(const JSONRPCRequest& request)
UniValue getmempoolancestors(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
- throw runtime_error(
+ throw std::runtime_error(
"getmempoolancestors txid (verbose)\n"
"\nIf txid is in the mempool, returns all in-mempool ancestors.\n"
"\nArguments:\n"
@@ -469,7 +470,7 @@ UniValue getmempoolancestors(const JSONRPCRequest& request)
}
bool fVerbose = false;
- if (request.params.size() > 1)
+ if (!request.params[1].isNull())
fVerbose = request.params[1].get_bool();
uint256 hash = ParseHashV(request.params[0], "parameter 1");
@@ -488,14 +489,14 @@ UniValue getmempoolancestors(const JSONRPCRequest& request)
if (!fVerbose) {
UniValue o(UniValue::VARR);
- BOOST_FOREACH(CTxMemPool::txiter ancestorIt, setAncestors) {
+ for (CTxMemPool::txiter ancestorIt : setAncestors) {
o.push_back(ancestorIt->GetTx().GetHash().ToString());
}
return o;
} else {
UniValue o(UniValue::VOBJ);
- BOOST_FOREACH(CTxMemPool::txiter ancestorIt, setAncestors) {
+ for (CTxMemPool::txiter ancestorIt : setAncestors) {
const CTxMemPoolEntry &e = *ancestorIt;
const uint256& _hash = e.GetTx().GetHash();
UniValue info(UniValue::VOBJ);
@@ -509,7 +510,7 @@ UniValue getmempoolancestors(const JSONRPCRequest& request)
UniValue getmempooldescendants(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
- throw runtime_error(
+ throw std::runtime_error(
"getmempooldescendants txid (verbose)\n"
"\nIf txid is in the mempool, returns all in-mempool descendants.\n"
"\nArguments:\n"
@@ -533,7 +534,7 @@ UniValue getmempooldescendants(const JSONRPCRequest& request)
}
bool fVerbose = false;
- if (request.params.size() > 1)
+ if (!request.params[1].isNull())
fVerbose = request.params[1].get_bool();
uint256 hash = ParseHashV(request.params[0], "parameter 1");
@@ -552,14 +553,14 @@ UniValue getmempooldescendants(const JSONRPCRequest& request)
if (!fVerbose) {
UniValue o(UniValue::VARR);
- BOOST_FOREACH(CTxMemPool::txiter descendantIt, setDescendants) {
+ for (CTxMemPool::txiter descendantIt : setDescendants) {
o.push_back(descendantIt->GetTx().GetHash().ToString());
}
return o;
} else {
UniValue o(UniValue::VOBJ);
- BOOST_FOREACH(CTxMemPool::txiter descendantIt, setDescendants) {
+ for (CTxMemPool::txiter descendantIt : setDescendants) {
const CTxMemPoolEntry &e = *descendantIt;
const uint256& _hash = e.GetTx().GetHash();
UniValue info(UniValue::VOBJ);
@@ -573,7 +574,7 @@ UniValue getmempooldescendants(const JSONRPCRequest& request)
UniValue getmempoolentry(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1) {
- throw runtime_error(
+ throw std::runtime_error(
"getmempoolentry txid\n"
"\nReturns mempool data for given transaction\n"
"\nArguments:\n"
@@ -606,7 +607,7 @@ UniValue getmempoolentry(const JSONRPCRequest& request)
UniValue getblockhash(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"getblockhash height\n"
"\nReturns hash of block in best-block-chain at height provided.\n"
"\nArguments:\n"
@@ -631,7 +632,7 @@ UniValue getblockhash(const JSONRPCRequest& request)
UniValue getblockheader(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
+ throw std::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"
@@ -668,7 +669,7 @@ UniValue getblockheader(const JSONRPCRequest& request)
uint256 hash(uint256S(strHash));
bool fVerbose = true;
- if (request.params.size() > 1)
+ if (!request.params[1].isNull())
fVerbose = request.params[1].get_bool();
if (mapBlockIndex.count(hash) == 0)
@@ -690,14 +691,17 @@ UniValue getblockheader(const JSONRPCRequest& request)
UniValue getblock(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
- "getblock \"blockhash\" ( verbose )\n"
- "\nIf verbose is false, returns a string that is serialized, hex-encoded data for block 'hash'.\n"
- "If verbose is true, returns an Object with information about block <hash>.\n"
+ throw std::runtime_error(
+ "getblock \"blockhash\" ( verbosity ) \n"
+ "\nIf verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.\n"
+ "If verbosity is 1, returns an Object with information about block <hash>.\n"
+ "If verbosity is 2, returns an Object with information about block <hash> and information about each transaction. \n"
"\nArguments:\n"
"1. \"blockhash\" (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"
+ "2. verbosity (numeric, optional, default=1) 0 for hex encoded data, 1 for a json object, and 2 for json object with transaction data\n"
+ "\nResult (for verbosity = 0):\n"
+ "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n"
+ "\nResult (for verbosity = 1):\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"
@@ -721,8 +725,14 @@ UniValue getblock(const JSONRPCRequest& request)
" \"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"
+ "\nResult (for verbosity = 2):\n"
+ "{\n"
+ " ..., Same output as verbosity = 1.\n"
+ " \"tx\" : [ (array of Objects) The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 \"tx\" result.\n"
+ " ,...\n"
+ " ],\n"
+ " ,... Same output as verbosity = 1.\n"
+ "}\n"
"\nExamples:\n"
+ HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
+ HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
@@ -733,9 +743,13 @@ UniValue getblock(const JSONRPCRequest& request)
std::string strHash = request.params[0].get_str();
uint256 hash(uint256S(strHash));
- bool fVerbose = true;
- if (request.params.size() > 1)
- fVerbose = request.params[1].get_bool();
+ int verbosity = 1;
+ if (!request.params[1].isNull()) {
+ if(request.params[1].isNum())
+ verbosity = request.params[1].get_int();
+ else
+ verbosity = request.params[1].get_bool() ? 1 : 0;
+ }
if (mapBlockIndex.count(hash) == 0)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
@@ -744,12 +758,17 @@ UniValue getblock(const JSONRPCRequest& request)
CBlockIndex* pblockindex = mapBlockIndex[hash];
if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0)
- throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)");
+ throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)");
- if(!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus()))
- throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
+ if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus()))
+ // Block not found on disk. This could be because we have the block
+ // header in our index but don't have the block (for example if a
+ // non-whitelisted node sends us an unrequested long chain of valid
+ // blocks, we add the headers to our index, but don't accept the
+ // block).
+ throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
- if (!fVerbose)
+ if (verbosity <= 0)
{
CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
ssBlock << block;
@@ -757,7 +776,7 @@ UniValue getblock(const JSONRPCRequest& request)
return strHex;
}
- return blockToJSON(block, pblockindex);
+ return blockToJSON(block, pblockindex, verbosity >= 2);
}
struct CCoinsStats
@@ -766,17 +785,37 @@ struct CCoinsStats
uint256 hashBlock;
uint64_t nTransactions;
uint64_t nTransactionOutputs;
- uint64_t nSerializedSize;
+ uint64_t nBogoSize;
uint256 hashSerialized;
+ uint64_t nDiskSize;
CAmount nTotalAmount;
- CCoinsStats() : nHeight(0), nTransactions(0), nTransactionOutputs(0), nSerializedSize(0), nTotalAmount(0) {}
+ CCoinsStats() : nHeight(0), nTransactions(0), nTransactionOutputs(0), nBogoSize(0), nDiskSize(0), nTotalAmount(0) {}
};
+static void ApplyStats(CCoinsStats &stats, CHashWriter& ss, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
+{
+ assert(!outputs.empty());
+ ss << hash;
+ ss << VARINT(outputs.begin()->second.nHeight * 2 + outputs.begin()->second.fCoinBase);
+ stats.nTransactions++;
+ for (const auto output : outputs) {
+ ss << VARINT(output.first + 1);
+ ss << output.second.out.scriptPubKey;
+ ss << VARINT(output.second.out.nValue);
+ stats.nTransactionOutputs++;
+ stats.nTotalAmount += output.second.out.nValue;
+ stats.nBogoSize += 32 /* txid */ + 4 /* vout index */ + 4 /* height + coinbase */ + 8 /* amount */ +
+ 2 /* scriptPubKey len */ + output.second.out.scriptPubKey.size() /* scriptPubKey */;
+ }
+ ss << VARINT(0);
+}
+
//! Calculate statistics about the unspent transaction output set
static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats)
{
std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor());
+ assert(pcursor);
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
stats.hashBlock = pcursor->GetBestBlock();
@@ -785,42 +824,40 @@ static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats)
stats.nHeight = mapBlockIndex.find(stats.hashBlock)->second->nHeight;
}
ss << stats.hashBlock;
- CAmount nTotalAmount = 0;
+ uint256 prevkey;
+ std::map<uint32_t, Coin> outputs;
while (pcursor->Valid()) {
boost::this_thread::interruption_point();
- uint256 key;
- CCoins coins;
- if (pcursor->GetKey(key) && pcursor->GetValue(coins)) {
- stats.nTransactions++;
- ss << key;
- for (unsigned int i=0; i<coins.vout.size(); i++) {
- const CTxOut &out = coins.vout[i];
- if (!out.IsNull()) {
- stats.nTransactionOutputs++;
- ss << VARINT(i+1);
- ss << out;
- nTotalAmount += out.nValue;
- }
+ COutPoint key;
+ Coin coin;
+ if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
+ if (!outputs.empty() && key.hash != prevkey) {
+ ApplyStats(stats, ss, prevkey, outputs);
+ outputs.clear();
}
- stats.nSerializedSize += 32 + pcursor->GetValueSize();
- ss << VARINT(0);
+ prevkey = key.hash;
+ outputs[key.n] = std::move(coin);
} else {
return error("%s: unable to read value", __func__);
}
pcursor->Next();
}
+ if (!outputs.empty()) {
+ ApplyStats(stats, ss, prevkey, outputs);
+ }
stats.hashSerialized = ss.GetHash();
- stats.nTotalAmount = nTotalAmount;
+ stats.nDiskSize = view->EstimateSize();
return true;
}
UniValue pruneblockchain(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"pruneblockchain\n"
"\nArguments:\n"
- "1. \"height\" (numeric, required) The block height to prune up to. May be set to a discrete height, or to a unix timestamp to prune based on block time.\n"
+ "1. \"height\" (numeric, required) The block height to prune up to. May be set to a discrete height, or a unix timestamp\n"
+ " to prune blocks whose block time is at least 2 hours older than the provided timestamp.\n"
"\nResult:\n"
"n (numeric) Height of the last block pruned.\n"
"\nExamples:\n"
@@ -828,7 +865,7 @@ UniValue pruneblockchain(const JSONRPCRequest& request)
+ HelpExampleRpc("pruneblockchain", "1000"));
if (!fPruneMode)
- throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Cannot prune blocks because node is not in prune mode.");
+ throw JSONRPCError(RPC_MISC_ERROR, "Cannot prune blocks because node is not in prune mode.");
LOCK(cs_main);
@@ -839,9 +876,10 @@ UniValue pruneblockchain(const JSONRPCRequest& request)
// Height value more than a billion is too high to be a block height, and
// too low to be a block time (corresponds to timestamp from Sep 2001).
if (heightParam > 1000000000) {
- CBlockIndex* pindex = chainActive.FindEarliestAtLeast(heightParam);
+ // Add a 2 hour buffer to include blocks which might have had old timestamps
+ CBlockIndex* pindex = chainActive.FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW);
if (!pindex) {
- throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not find block with at least the specified timestamp.");
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Could not find block with at least the specified timestamp.");
}
heightParam = pindex->nHeight;
}
@@ -849,11 +887,11 @@ UniValue pruneblockchain(const JSONRPCRequest& request)
unsigned int height = (unsigned int) heightParam;
unsigned int chainHeight = (unsigned int) chainActive.Height();
if (chainHeight < Params().PruneAfterHeight())
- throw JSONRPCError(RPC_INTERNAL_ERROR, "Blockchain is too short for pruning.");
+ throw JSONRPCError(RPC_MISC_ERROR, "Blockchain is too short for pruning.");
else if (height > chainHeight)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Blockchain is shorter than the attempted prune height.");
else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) {
- LogPrint("rpc", "Attempt to prune blocks close to the tip. Retaining the minimum number of blocks.");
+ LogPrint(BCLog::RPC, "Attempt to prune blocks close to the tip. Retaining the minimum number of blocks.");
height = chainHeight - MIN_BLOCKS_TO_KEEP;
}
@@ -864,7 +902,7 @@ UniValue pruneblockchain(const JSONRPCRequest& request)
UniValue gettxoutsetinfo(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"gettxoutsetinfo\n"
"\nReturns statistics about the unspent transaction output set.\n"
"Note this call may take some time.\n"
@@ -874,8 +912,9 @@ UniValue gettxoutsetinfo(const JSONRPCRequest& request)
" \"bestblock\": \"hex\", (string) the best block hash hex\n"
" \"transactions\": n, (numeric) The number of transactions\n"
" \"txouts\": n, (numeric) The number of output transactions\n"
- " \"bytes_serialized\": n, (numeric) The serialized size\n"
- " \"hash_serialized\": \"hash\", (string) The serialized hash\n"
+ " \"bogosize\": n, (numeric) A meaningless metric for UTXO set size\n"
+ " \"hash_serialized_2\": \"hash\", (string) The serialized hash\n"
+ " \"disk_size\": n, (numeric) The estimated size of the chainstate on disk\n"
" \"total_amount\": x.xxx (numeric) The total amount\n"
"}\n"
"\nExamples:\n"
@@ -887,13 +926,14 @@ UniValue gettxoutsetinfo(const JSONRPCRequest& request)
CCoinsStats stats;
FlushStateToDisk();
- if (GetUTXOStats(pcoinsTip, stats)) {
+ if (GetUTXOStats(pcoinsdbview, stats)) {
ret.push_back(Pair("height", (int64_t)stats.nHeight));
ret.push_back(Pair("bestblock", stats.hashBlock.GetHex()));
ret.push_back(Pair("transactions", (int64_t)stats.nTransactions));
ret.push_back(Pair("txouts", (int64_t)stats.nTransactionOutputs));
- ret.push_back(Pair("bytes_serialized", (int64_t)stats.nSerializedSize));
- ret.push_back(Pair("hash_serialized", stats.hashSerialized.GetHex()));
+ ret.push_back(Pair("bogosize", (int64_t)stats.nBogoSize));
+ ret.push_back(Pair("hash_serialized_2", stats.hashSerialized.GetHex()));
+ ret.push_back(Pair("disk_size", stats.nDiskSize));
ret.push_back(Pair("total_amount", ValueFromAmount(stats.nTotalAmount)));
} else {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
@@ -904,13 +944,14 @@ UniValue gettxoutsetinfo(const JSONRPCRequest& request)
UniValue gettxout(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
- throw runtime_error(
+ throw std::runtime_error(
"gettxout \"txid\" n ( include_mempool )\n"
"\nReturns details about an unspent transaction output.\n"
"\nArguments:\n"
- "1. \"txid\" (string, required) The transaction id\n"
- "2. n (numeric, required) vout number\n"
- "3. include_mempool (boolean, optional) Whether to include the mempool\n"
+ "1. \"txid\" (string, required) The transaction id\n"
+ "2. \"n\" (numeric, required) vout number\n"
+ "3. \"include_mempool\" (boolean, optional) Whether to include the mempool. Default: true."
+ " Note that an unspent output that is spent in the mempool won't appear.\n"
"\nResult:\n"
"{\n"
" \"bestblock\" : \"hash\", (string) the block hash\n"
@@ -926,7 +967,6 @@ UniValue gettxout(const JSONRPCRequest& request)
" ,...\n"
" ]\n"
" },\n"
- " \"version\" : n, (numeric) The version\n"
" \"coinbase\" : true|false (boolean) Coinbase or not\n"
"}\n"
@@ -946,47 +986,47 @@ UniValue gettxout(const JSONRPCRequest& request)
std::string strHash = request.params[0].get_str();
uint256 hash(uint256S(strHash));
int n = request.params[1].get_int();
+ COutPoint out(hash, n);
bool fMempool = true;
- if (request.params.size() > 2)
+ if (!request.params[2].isNull())
fMempool = request.params[2].get_bool();
- CCoins coins;
+ Coin coin;
if (fMempool) {
LOCK(mempool.cs);
CCoinsViewMemPool view(pcoinsTip, mempool);
- if (!view.GetCoins(hash, coins))
+ if (!view.GetCoin(out, coin) || mempool.isSpent(out)) {
return NullUniValue;
- mempool.pruneSpent(hash, coins); // TODO: this should be done by the CCoinsViewMemPool
+ }
} else {
- if (!pcoinsTip->GetCoins(hash, coins))
+ if (!pcoinsTip->GetCoin(out, coin)) {
return NullUniValue;
+ }
}
- if (n<0 || (unsigned int)n>=coins.vout.size() || coins.vout[n].IsNull())
- return NullUniValue;
BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
CBlockIndex *pindex = it->second;
ret.push_back(Pair("bestblock", pindex->GetBlockHash().GetHex()));
- if ((unsigned int)coins.nHeight == MEMPOOL_HEIGHT)
+ if (coin.nHeight == MEMPOOL_HEIGHT) {
ret.push_back(Pair("confirmations", 0));
- else
- ret.push_back(Pair("confirmations", pindex->nHeight - coins.nHeight + 1));
- ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue)));
+ } else {
+ ret.push_back(Pair("confirmations", (int64_t)(pindex->nHeight - coin.nHeight + 1)));
+ }
+ ret.push_back(Pair("value", ValueFromAmount(coin.out.nValue)));
UniValue o(UniValue::VOBJ);
- ScriptPubKeyToJSON(coins.vout[n].scriptPubKey, o, true);
+ ScriptPubKeyToUniv(coin.out.scriptPubKey, o, true);
ret.push_back(Pair("scriptPubKey", o));
- ret.push_back(Pair("version", coins.nVersion));
- ret.push_back(Pair("coinbase", coins.fCoinBase));
+ ret.push_back(Pair("coinbase", (bool)coin.fCoinBase));
return ret;
}
UniValue verifychain(const JSONRPCRequest& request)
{
- int nCheckLevel = GetArg("-checklevel", DEFAULT_CHECKLEVEL);
- int nCheckDepth = GetArg("-checkblocks", DEFAULT_CHECKBLOCKS);
+ int nCheckLevel = gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL);
+ int nCheckDepth = gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS);
if (request.fHelp || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"verifychain ( checklevel nblocks )\n"
"\nVerifies blockchain database.\n"
"\nArguments:\n"
@@ -1001,9 +1041,9 @@ UniValue verifychain(const JSONRPCRequest& request)
LOCK(cs_main);
- if (request.params.size() > 0)
+ if (!request.params[0].isNull())
nCheckLevel = request.params[0].get_int();
- if (request.params.size() > 1)
+ if (!request.params[1].isNull())
nCheckDepth = request.params[1].get_int();
return CVerifyDB().VerifyDB(Params(), pcoinsTip, nCheckLevel, nCheckDepth);
@@ -1057,6 +1097,17 @@ static UniValue BIP9SoftForkDesc(const Consensus::Params& consensusParams, Conse
rv.push_back(Pair("startTime", consensusParams.vDeployments[id].nStartTime));
rv.push_back(Pair("timeout", consensusParams.vDeployments[id].nTimeout));
rv.push_back(Pair("since", VersionBitsTipStateSinceHeight(consensusParams, id)));
+ if (THRESHOLD_STARTED == thresholdState)
+ {
+ UniValue statsUV(UniValue::VOBJ);
+ BIP9Stats statsStruct = VersionBitsTipStatistics(consensusParams, id);
+ statsUV.push_back(Pair("period", statsStruct.period));
+ statsUV.push_back(Pair("threshold", statsStruct.threshold));
+ statsUV.push_back(Pair("elapsed", statsStruct.elapsed));
+ statsUV.push_back(Pair("count", statsStruct.count));
+ statsUV.push_back(Pair("possible", statsStruct.possible));
+ rv.push_back(Pair("statistics", statsUV));
+ }
return rv;
}
@@ -1072,7 +1123,7 @@ void BIP9SoftForkDescPushBack(UniValue& bip9_softforks, const std::string &name,
UniValue getblockchaininfo(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getblockchaininfo\n"
"Returns an object containing various state info regarding blockchain processing.\n"
"\nResult:\n"
@@ -1102,9 +1153,17 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
" \"bit\": xx, (numeric) the bit (0-28) in the block version field used to signal this softfork (only for \"started\" status)\n"
" \"startTime\": xx, (numeric) the minimum median time past of a block at which the bit gains its meaning\n"
" \"timeout\": xx, (numeric) the median time past of a block at which the deployment is considered failed if not yet locked in\n"
- " \"since\": xx (numeric) height of the first block to which the status applies\n"
+ " \"since\": xx, (numeric) height of the first block to which the status applies\n"
+ " \"statistics\": { (object) numeric statistics about BIP9 signalling for a softfork (only for \"started\" status)\n"
+ " \"period\": xx, (numeric) the length in blocks of the BIP9 signalling period \n"
+ " \"threshold\": xx, (numeric) the number of blocks with the version bit set required to activate the feature \n"
+ " \"elapsed\": xx, (numeric) the number of blocks elapsed since the beginning of the current period \n"
+ " \"count\": xx, (numeric) the number of blocks with the version bit set in the current period \n"
+ " \"possible\": xx (boolean) returns false if there are not enough blocks left in this period to pass activation threshold \n"
+ " }\n"
" }\n"
" }\n"
+ " \"warnings\" : \"...\", (string) any network and blockchain warnings.\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getblockchaininfo", "")
@@ -1144,6 +1203,7 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
obj.push_back(Pair("pruneheight", block->nHeight));
}
+ obj.push_back(Pair("warnings", GetWarnings("statusbar")));
return obj;
}
@@ -1165,7 +1225,7 @@ struct CompareBlocksByHeight
UniValue getchaintips(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getchaintips\n"
"Return information about all known tips in the block tree,"
" including the main chain as well as orphaned branches.\n"
@@ -1198,7 +1258,7 @@ UniValue getchaintips(const JSONRPCRequest& request)
LOCK(cs_main);
/*
- * Idea: the set of chain tips is chainActive.tip, plus orphan blocks which do not have another orphan building off of them.
+ * Idea: the set of chain tips is chainActive.tip, plus orphan blocks which do not have another orphan building off of them.
* Algorithm:
* - Make one pass through mapBlockIndex, picking out the orphan blocks, and also storing a set of the orphan block's pprev pointers.
* - Iterate through the orphan blocks. If the block isn't pointed to by another orphan, it is a chain tip.
@@ -1208,7 +1268,7 @@ UniValue getchaintips(const JSONRPCRequest& request)
std::set<const CBlockIndex*> setOrphans;
std::set<const CBlockIndex*> setPrevs;
- BOOST_FOREACH(const PAIRTYPE(const uint256, CBlockIndex*)& item, mapBlockIndex)
+ for (const std::pair<const uint256, CBlockIndex*>& item : mapBlockIndex)
{
if (!chainActive.Contains(item.second)) {
setOrphans.insert(item.second);
@@ -1228,7 +1288,7 @@ UniValue getchaintips(const JSONRPCRequest& request)
/* Construct the output array. */
UniValue res(UniValue::VARR);
- BOOST_FOREACH(const CBlockIndex* block, setTips)
+ for (const CBlockIndex* block : setTips)
{
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("height", block->nHeight));
@@ -1237,7 +1297,7 @@ UniValue getchaintips(const JSONRPCRequest& request)
const int branchLen = block->nHeight - chainActive.FindFork(block)->nHeight;
obj.push_back(Pair("branchlen", branchLen));
- string status;
+ std::string status;
if (chainActive.Contains(block)) {
// This block is part of the currently active chain.
status = "active";
@@ -1271,7 +1331,7 @@ UniValue mempoolInfoToJSON()
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()));
- size_t maxmempool = GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
+ size_t maxmempool = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
ret.push_back(Pair("maxmempool", (int64_t) maxmempool));
ret.push_back(Pair("mempoolminfee", ValueFromAmount(mempool.GetMinFee(maxmempool).GetFeePerK())));
@@ -1281,7 +1341,7 @@ UniValue mempoolInfoToJSON()
UniValue getmempoolinfo(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getmempoolinfo\n"
"\nReturns details on the active state of the TX memory pool.\n"
"\nResult:\n"
@@ -1290,7 +1350,7 @@ UniValue getmempoolinfo(const JSONRPCRequest& request)
" \"bytes\": xxxxx, (numeric) Sum of all virtual transaction sizes as defined in BIP 141. Differs from actual serialized size because witness data is discounted\n"
" \"usage\": xxxxx, (numeric) Total memory usage for the mempool\n"
" \"maxmempool\": xxxxx, (numeric) Maximum memory usage for the mempool\n"
- " \"mempoolminfee\": xxxxx (numeric) Minimum fee for tx to be accepted\n"
+ " \"mempoolminfee\": xxxxx (numeric) Minimum fee rate in " + CURRENCY_UNIT + "/kB for tx to be accepted\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getmempoolinfo", "")
@@ -1303,7 +1363,7 @@ UniValue getmempoolinfo(const JSONRPCRequest& request)
UniValue preciousblock(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"preciousblock \"blockhash\"\n"
"\nTreats a block as if it were received before others with the same work.\n"
"\nA later preciousblock call can override the effect of an earlier one.\n"
@@ -1341,7 +1401,7 @@ UniValue preciousblock(const JSONRPCRequest& request)
UniValue invalidateblock(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"invalidateblock \"blockhash\"\n"
"\nPermanently marks a block as invalid, as if it violated a consensus rule.\n"
"\nArguments:\n"
@@ -1379,7 +1439,7 @@ UniValue invalidateblock(const JSONRPCRequest& request)
UniValue reconsiderblock(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"reconsiderblock \"blockhash\"\n"
"\nRemoves invalidity status of a block and its descendants, reconsider them for activation.\n"
"This can be used to undo the effects of invalidateblock.\n"
@@ -1413,35 +1473,135 @@ UniValue reconsiderblock(const JSONRPCRequest& request)
return NullUniValue;
}
+UniValue getchaintxstats(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() > 2)
+ throw std::runtime_error(
+ "getchaintxstats ( nblocks blockhash )\n"
+ "\nCompute statistics about the total number and rate of transactions in the chain.\n"
+ "\nArguments:\n"
+ "1. nblocks (numeric, optional) Size of the window in number of blocks (default: one month).\n"
+ "2. \"blockhash\" (string, optional) The hash of the block that ends the window.\n"
+ "\nResult:\n"
+ "{\n"
+ " \"time\": xxxxx, (numeric) The timestamp for the final block in the window in UNIX format.\n"
+ " \"txcount\": xxxxx, (numeric) The total number of transactions in the chain up to that point.\n"
+ " \"window_block_count\": xxxxx, (numeric) Size of the window in number of blocks.\n"
+ " \"window_tx_count\": xxxxx, (numeric) The number of transactions in the window. Only returned if \"window_block_count\" is > 0.\n"
+ " \"window_interval\": xxxxx, (numeric) The elapsed time in the window in seconds. Only returned if \"window_block_count\" is > 0.\n"
+ " \"txrate\": x.xx, (numeric) The average rate of transactions per second in the window. Only returned if \"window_interval\" is > 0.\n"
+ "}\n"
+ "\nExamples:\n"
+ + HelpExampleCli("getchaintxstats", "")
+ + HelpExampleRpc("getchaintxstats", "2016")
+ );
+
+ const CBlockIndex* pindex;
+ int blockcount = 30 * 24 * 60 * 60 / Params().GetConsensus().nPowTargetSpacing; // By default: 1 month
+
+ bool havehash = !request.params[1].isNull();
+ uint256 hash;
+ if (havehash) {
+ hash = uint256S(request.params[1].get_str());
+ }
+
+ {
+ LOCK(cs_main);
+ if (havehash) {
+ auto it = mapBlockIndex.find(hash);
+ if (it == mapBlockIndex.end()) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
+ }
+ pindex = it->second;
+ if (!chainActive.Contains(pindex)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Block is not in main chain");
+ }
+ } else {
+ pindex = chainActive.Tip();
+ }
+ }
+
+ assert(pindex != nullptr);
+
+ if (request.params[0].isNull()) {
+ blockcount = std::max(0, std::min(blockcount, pindex->nHeight - 1));
+ } else {
+ blockcount = request.params[0].get_int();
+
+ if (blockcount < 0 || (blockcount > 0 && blockcount >= pindex->nHeight)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block count: should be between 0 and the block's height - 1");
+ }
+ }
+
+ const CBlockIndex* pindexPast = pindex->GetAncestor(pindex->nHeight - blockcount);
+ int nTimeDiff = pindex->GetMedianTimePast() - pindexPast->GetMedianTimePast();
+ int nTxDiff = pindex->nChainTx - pindexPast->nChainTx;
+
+ UniValue ret(UniValue::VOBJ);
+ ret.push_back(Pair("time", (int64_t)pindex->nTime));
+ ret.push_back(Pair("txcount", (int64_t)pindex->nChainTx));
+ ret.push_back(Pair("window_block_count", blockcount));
+ if (blockcount > 0) {
+ ret.push_back(Pair("window_tx_count", nTxDiff));
+ ret.push_back(Pair("window_interval", nTimeDiff));
+ if (nTimeDiff > 0) {
+ ret.push_back(Pair("txrate", ((double)nTxDiff) / nTimeDiff));
+ }
+ }
+
+ return ret;
+}
+
+UniValue savemempool(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() != 0) {
+ throw std::runtime_error(
+ "savemempool\n"
+ "\nDumps the mempool to disk.\n"
+ "\nExamples:\n"
+ + HelpExampleCli("savemempool", "")
+ + HelpExampleRpc("savemempool", "")
+ );
+ }
+
+ if (!DumpMempool()) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Unable to dump mempool to disk");
+ }
+
+ return NullUniValue;
+}
+
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafe argNames
- // --------------------- ------------------------ ----------------------- ------ ----------
- { "blockchain", "getblockchaininfo", &getblockchaininfo, true, {} },
- { "blockchain", "getbestblockhash", &getbestblockhash, true, {} },
- { "blockchain", "getblockcount", &getblockcount, true, {} },
- { "blockchain", "getblock", &getblock, true, {"blockhash","verbose"} },
- { "blockchain", "getblockhash", &getblockhash, true, {"height"} },
- { "blockchain", "getblockheader", &getblockheader, true, {"blockhash","verbose"} },
- { "blockchain", "getchaintips", &getchaintips, true, {} },
- { "blockchain", "getdifficulty", &getdifficulty, true, {} },
- { "blockchain", "getmempoolancestors", &getmempoolancestors, true, {"txid","verbose"} },
- { "blockchain", "getmempooldescendants", &getmempooldescendants, true, {"txid","verbose"} },
- { "blockchain", "getmempoolentry", &getmempoolentry, true, {"txid"} },
- { "blockchain", "getmempoolinfo", &getmempoolinfo, true, {} },
- { "blockchain", "getrawmempool", &getrawmempool, true, {"verbose"} },
- { "blockchain", "gettxout", &gettxout, true, {"txid","n","include_mempool"} },
- { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true, {} },
- { "blockchain", "pruneblockchain", &pruneblockchain, true, {"height"} },
- { "blockchain", "verifychain", &verifychain, true, {"checklevel","nblocks"} },
-
- { "blockchain", "preciousblock", &preciousblock, true, {"blockhash"} },
+{ // category name actor (function) argNames
+ // --------------------- ------------------------ ----------------------- ----------
+ { "blockchain", "getblockchaininfo", &getblockchaininfo, {} },
+ { "blockchain", "getchaintxstats", &getchaintxstats, {"nblocks", "blockhash"} },
+ { "blockchain", "getbestblockhash", &getbestblockhash, {} },
+ { "blockchain", "getblockcount", &getblockcount, {} },
+ { "blockchain", "getblock", &getblock, {"blockhash","verbosity|verbose"} },
+ { "blockchain", "getblockhash", &getblockhash, {"height"} },
+ { "blockchain", "getblockheader", &getblockheader, {"blockhash","verbose"} },
+ { "blockchain", "getchaintips", &getchaintips, {} },
+ { "blockchain", "getdifficulty", &getdifficulty, {} },
+ { "blockchain", "getmempoolancestors", &getmempoolancestors, {"txid","verbose"} },
+ { "blockchain", "getmempooldescendants", &getmempooldescendants, {"txid","verbose"} },
+ { "blockchain", "getmempoolentry", &getmempoolentry, {"txid"} },
+ { "blockchain", "getmempoolinfo", &getmempoolinfo, {} },
+ { "blockchain", "getrawmempool", &getrawmempool, {"verbose"} },
+ { "blockchain", "gettxout", &gettxout, {"txid","n","include_mempool"} },
+ { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, {} },
+ { "blockchain", "pruneblockchain", &pruneblockchain, {"height"} },
+ { "blockchain", "savemempool", &savemempool, {} },
+ { "blockchain", "verifychain", &verifychain, {"checklevel","nblocks"} },
+
+ { "blockchain", "preciousblock", &preciousblock, {"blockhash"} },
/* Not shown in help */
- { "hidden", "invalidateblock", &invalidateblock, true, {"blockhash"} },
- { "hidden", "reconsiderblock", &reconsiderblock, true, {"blockhash"} },
- { "hidden", "waitfornewblock", &waitfornewblock, true, {"timeout"} },
- { "hidden", "waitforblock", &waitforblock, true, {"blockhash","timeout"} },
- { "hidden", "waitforblockheight", &waitforblockheight, true, {"height","timeout"} },
+ { "hidden", "invalidateblock", &invalidateblock, {"blockhash"} },
+ { "hidden", "reconsiderblock", &reconsiderblock, {"blockhash"} },
+ { "hidden", "waitfornewblock", &waitfornewblock, {"timeout"} },
+ { "hidden", "waitforblock", &waitforblock, {"blockhash","timeout"} },
+ { "hidden", "waitforblockheight", &waitforblockheight, {"height","timeout"} },
};
void RegisterBlockchainRPCCommands(CRPCTable &t)
diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h
new file mode 100644
index 0000000000..960edfd56f
--- /dev/null
+++ b/src/rpc/blockchain.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2017 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_RPC_BLOCKCHAIN_H
+#define BITCOIN_RPC_BLOCKCHAIN_H
+
+class CBlock;
+class CBlockIndex;
+class UniValue;
+
+/**
+ * Get the difficulty of the net wrt to the given block index, or the chain tip if
+ * not provided.
+ *
+ * @return A floating point number that is a multiple of the main net minimum
+ * difficulty (4295032833 hashes).
+ */
+double GetDifficulty(const CBlockIndex* blockindex = nullptr);
+
+/** Callback for when block tip changed. */
+void RPCNotifyBlockChange(bool ibd, const CBlockIndex *);
+
+/** Block description to JSON */
+UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false);
+
+/** Mempool information to JSON */
+UniValue mempoolInfoToJSON();
+
+/** Mempool to JSON */
+UniValue mempoolToJSON(bool fVerbose = false);
+
+/** Block header to JSON */
+UniValue blockheaderToJSON(const CBlockIndex* blockindex);
+
+#endif
+
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index 5d3c458455..f54f24e2a7 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -10,11 +10,8 @@
#include <set>
#include <stdint.h>
-#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
#include <univalue.h>
-using namespace std;
-
class CRPCConvertParam
{
public:
@@ -24,7 +21,7 @@ public:
};
/**
- * Specifiy a (method, idx, name) here if the argument is a non-string RPC
+ * Specify a (method, idx, name) here if the argument is a non-string RPC
* argument and needs to be converted from JSON.
*
* @note Parameter indexes start from 0.
@@ -40,6 +37,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "getnetworkhashps", 1, "height" },
{ "sendtoaddress", 1, "amount" },
{ "sendtoaddress", 4, "subtractfeefromamount" },
+ { "sendtoaddress", 5 , "replaceable" },
+ { "sendtoaddress", 6 , "conf_target" },
{ "settxfee", 0, "amount" },
{ "getreceivedbyaddress", 1, "minconf" },
{ "getreceivedbyaccount", 1, "minconf" },
@@ -69,9 +68,12 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "getblocktemplate", 0, "template_request" },
{ "listsinceblock", 1, "target_confirmations" },
{ "listsinceblock", 2, "include_watchonly" },
+ { "listsinceblock", 3, "include_removed" },
{ "sendmany", 1, "amounts" },
{ "sendmany", 2, "minconf" },
{ "sendmany", 4, "subtractfeefrom" },
+ { "sendmany", 5 , "replaceable" },
+ { "sendmany", 6 , "conf_target" },
{ "addmultisigaddress", 0, "nrequired" },
{ "addmultisigaddress", 1, "keys" },
{ "createmultisig", 0, "nrequired" },
@@ -79,16 +81,22 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "listunspent", 0, "minconf" },
{ "listunspent", 1, "maxconf" },
{ "listunspent", 2, "addresses" },
+ { "listunspent", 3, "include_unsafe" },
+ { "listunspent", 4, "query_options" },
+ { "getblock", 1, "verbosity" },
{ "getblock", 1, "verbose" },
{ "getblockheader", 1, "verbose" },
+ { "getchaintxstats", 0, "nblocks" },
{ "gettransaction", 1, "include_watchonly" },
{ "getrawtransaction", 1, "verbose" },
- { "createrawtransaction", 0, "transactions" },
+ { "createrawtransaction", 0, "inputs" },
{ "createrawtransaction", 1, "outputs" },
{ "createrawtransaction", 2, "locktime" },
+ { "createrawtransaction", 3, "replaceable" },
{ "signrawtransaction", 1, "prevtxs" },
{ "signrawtransaction", 2, "privkeys" },
{ "sendrawtransaction", 1, "allowhighfees" },
+ { "combinerawtransaction", 0, "txs" },
{ "fundrawtransaction", 1, "options" },
{ "gettxout", 1, "n" },
{ "gettxout", 2, "include_mempool" },
@@ -107,16 +115,21 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "keypoolrefill", 0, "newsize" },
{ "getrawmempool", 0, "verbose" },
{ "estimatefee", 0, "nblocks" },
- { "estimatepriority", 0, "nblocks" },
- { "estimatesmartfee", 0, "nblocks" },
- { "estimatesmartpriority", 0, "nblocks" },
- { "prioritisetransaction", 1, "priority_delta" },
+ { "estimatesmartfee", 0, "conf_target" },
+ { "estimaterawfee", 0, "conf_target" },
+ { "estimaterawfee", 1, "threshold" },
+ { "prioritisetransaction", 1, "dummy" },
{ "prioritisetransaction", 2, "fee_delta" },
{ "setban", 2, "bantime" },
{ "setban", 3, "absolute" },
{ "setnetworkactive", 0, "state" },
{ "getmempoolancestors", 1, "verbose" },
{ "getmempooldescendants", 1, "verbose" },
+ { "bumpfee", 1, "options" },
+ { "logging", 0, "include" },
+ { "logging", 1, "exclude" },
+ { "disconnectnode", 1, "nodeid" },
+ { "addwitnessaddress", 1, "p2sh" },
// Echo with conversion (For testing only)
{ "echojson", 0, "arg0" },
{ "echojson", 1, "arg1" },
@@ -170,7 +183,7 @@ 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);
+ throw std::runtime_error(std::string("Error parsing JSON:")+strVal);
return jVal[0];
}
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index e46f55a8aa..f79439f038 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -15,22 +15,31 @@
#include "validation.h"
#include "miner.h"
#include "net.h"
+#include "policy/fees.h"
#include "pow.h"
+#include "rpc/blockchain.h"
+#include "rpc/mining.h"
#include "rpc/server.h"
#include "txmempool.h"
#include "util.h"
#include "utilstrencodings.h"
#include "validationinterface.h"
+#include "warnings.h"
#include <memory>
#include <stdint.h>
-#include <boost/assign/list_of.hpp>
-#include <boost/shared_ptr.hpp>
-
#include <univalue.h>
-using namespace std;
+unsigned int ParseConfirmTarget(const UniValue& value)
+{
+ int target = value.get_int();
+ unsigned int max_target = ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
+ if (target < 1 || (unsigned int)target > max_target) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid conf_target, must be between %u - %u", 1, max_target));
+ }
+ return (unsigned int)target;
+}
/**
* Return average network hashes per second based on the last 'lookup' blocks,
@@ -43,7 +52,7 @@ UniValue GetNetworkHashPS(int lookup, int height) {
if (height >= 0 && height < chainActive.Height())
pb = chainActive[height];
- if (pb == NULL || !pb->nHeight)
+ if (pb == nullptr || !pb->nHeight)
return 0;
// If lookup is -1, then use blocks since last difficulty change.
@@ -77,7 +86,7 @@ UniValue GetNetworkHashPS(int lookup, int height) {
UniValue getnetworkhashps(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"getnetworkhashps ( nblocks height )\n"
"\nReturns the estimated network hashes per second based on the last n blocks.\n"
"Pass in [blocks] to override # of blocks, -1 specifies since last difficulty change.\n"
@@ -93,21 +102,19 @@ UniValue getnetworkhashps(const JSONRPCRequest& request)
);
LOCK(cs_main);
- return GetNetworkHashPS(request.params.size() > 0 ? request.params[0].get_int() : 120, request.params.size() > 1 ? request.params[1].get_int() : -1);
+ return GetNetworkHashPS(!request.params[0].isNull() ? request.params[0].get_int() : 120, !request.params[1].isNull() ? request.params[1].get_int() : -1);
}
-UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nGenerate, uint64_t nMaxTries, bool keepScript)
+UniValue generateBlocks(std::shared_ptr<CReserveScript> coinbaseScript, int nGenerate, uint64_t nMaxTries, bool keepScript)
{
static const int nInnerLoopCount = 0x10000;
- int nHeightStart = 0;
int nHeightEnd = 0;
int nHeight = 0;
{ // Don't keep cs_main locked
LOCK(cs_main);
- nHeightStart = chainActive.Height();
- nHeight = nHeightStart;
- nHeightEnd = nHeightStart+nGenerate;
+ nHeight = chainActive.Height();
+ nHeightEnd = nHeight+nGenerate;
}
unsigned int nExtraNonce = 0;
UniValue blockHashes(UniValue::VARR);
@@ -132,7 +139,7 @@ UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nG
continue;
}
std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(*pblock);
- if (!ProcessNewBlock(Params(), shared_pblock, true, NULL))
+ if (!ProcessNewBlock(Params(), shared_pblock, true, nullptr))
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
++nHeight;
blockHashes.push_back(pblock->GetHash().GetHex());
@@ -146,46 +153,10 @@ UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nG
return blockHashes;
}
-UniValue generate(const JSONRPCRequest& request)
-{
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
- "generate nblocks ( maxtries )\n"
- "\nMine up to nblocks blocks immediately (before the RPC call returns)\n"
- "\nArguments:\n"
- "1. nblocks (numeric, required) How many blocks are generated immediately.\n"
- "2. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n"
- "\nResult:\n"
- "[ blockhashes ] (array) hashes of blocks generated\n"
- "\nExamples:\n"
- "\nGenerate 11 blocks\n"
- + HelpExampleCli("generate", "11")
- );
-
- int nGenerate = request.params[0].get_int();
- uint64_t nMaxTries = 1000000;
- if (request.params.size() > 1) {
- nMaxTries = request.params[1].get_int();
- }
-
- 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)");
-
- return generateBlocks(coinbaseScript, nGenerate, nMaxTries, true);
-}
-
UniValue generatetoaddress(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
- throw runtime_error(
+ throw std::runtime_error(
"generatetoaddress nblocks address (maxtries)\n"
"\nMine blocks immediately to a specified address (before the RPC call returns)\n"
"\nArguments:\n"
@@ -201,16 +172,17 @@ UniValue generatetoaddress(const JSONRPCRequest& request)
int nGenerate = request.params[0].get_int();
uint64_t nMaxTries = 1000000;
- if (request.params.size() > 2) {
+ if (!request.params[2].isNull()) {
nMaxTries = request.params[2].get_int();
}
- CBitcoinAddress address(request.params[1].get_str());
- if (!address.IsValid())
+ CTxDestination destination = DecodeDestination(request.params[1].get_str());
+ if (!IsValidDestination(destination)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address");
-
- boost::shared_ptr<CReserveScript> coinbaseScript(new CReserveScript());
- coinbaseScript->reserveScript = GetScriptForDestination(address.Get());
+ }
+
+ std::shared_ptr<CReserveScript> coinbaseScript = std::make_shared<CReserveScript>();
+ coinbaseScript->reserveScript = GetScriptForDestination(destination);
return generateBlocks(coinbaseScript, nGenerate, nMaxTries, false);
}
@@ -218,20 +190,20 @@ UniValue generatetoaddress(const JSONRPCRequest& request)
UniValue getmininginfo(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getmininginfo\n"
"\nReturns a json object containing mining-related information."
"\nResult:\n"
"{\n"
" \"blocks\": nnn, (numeric) The current block\n"
- " \"currentblocksize\": nnn, (numeric) The last block size\n"
" \"currentblockweight\": nnn, (numeric) The last block weight\n"
" \"currentblocktx\": nnn, (numeric) The last block transaction\n"
" \"difficulty\": xxx.xxxxx (numeric) The current difficulty\n"
- " \"errors\": \"...\" (string) Current errors\n"
" \"networkhashps\": nnn, (numeric) The network hashes per second\n"
" \"pooledtx\": n (numeric) The size of the mempool\n"
" \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
+ " \"warnings\": \"...\" (string) any network and blockchain warnings\n"
+ " \"errors\": \"...\" (string) DEPRECATED. Same as warnings. Only shown when bitcoind is started with -deprecatedrpc=getmininginfo\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getmininginfo", "")
@@ -243,14 +215,17 @@ UniValue getmininginfo(const JSONRPCRequest& request)
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("blocks", (int)chainActive.Height()));
- obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize));
obj.push_back(Pair("currentblockweight", (uint64_t)nLastBlockWeight));
obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
- obj.push_back(Pair("errors", GetWarnings("statusbar")));
obj.push_back(Pair("networkhashps", getnetworkhashps(request)));
obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
obj.push_back(Pair("chain", Params().NetworkIDString()));
+ if (IsDeprecatedRPCEnabled("getmininginfo")) {
+ obj.push_back(Pair("errors", GetWarnings("statusbar")));
+ } else {
+ obj.push_back(Pair("warnings", GetWarnings("statusbar")));
+ }
return obj;
}
@@ -259,14 +234,13 @@ UniValue getmininginfo(const JSONRPCRequest& request)
UniValue prioritisetransaction(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 3)
- throw runtime_error(
- "prioritisetransaction <txid> <priority delta> <fee delta>\n"
+ throw std::runtime_error(
+ "prioritisetransaction <txid> <dummy value> <fee delta>\n"
"Accepts the transaction into mined blocks at a higher (or lower) priority\n"
"\nArguments:\n"
"1. \"txid\" (string, required) The transaction id.\n"
- "2. priority_delta (numeric, required) The priority to add or subtract.\n"
- " The transaction selection algorithm considers the tx as it would have a higher priority.\n"
- " (priority of a transaction is calculated: coinage * value_in_satoshis / txsize) \n"
+ "2. dummy (numeric, optional) API-Compatibility for previous API. Must be zero or null.\n"
+ " DEPRECATED. For forward compatibility use named arguments and omit this parameter.\n"
"3. fee_delta (numeric, required) The fee value (in satoshis) to add (or subtract, if negative).\n"
" The fee is not actually paid, only the algorithm for selecting transactions into a block\n"
" considers the transaction as it would have paid a higher (or lower) fee.\n"
@@ -282,7 +256,11 @@ UniValue prioritisetransaction(const JSONRPCRequest& request)
uint256 hash = ParseHashStr(request.params[0].get_str(), "txid");
CAmount nAmount = request.params[2].get_int64();
- mempool.PrioritiseTransaction(hash, request.params[0].get_str(), request.params[1].get_real(), nAmount);
+ if (!(request.params[1].isNull() || request.params[1].get_real() == 0)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Priority is no longer supported, dummy argument to prioritisetransaction must be 0.");
+ }
+
+ mempool.PrioritiseTransaction(hash, nAmount);
return true;
}
@@ -307,7 +285,7 @@ static UniValue BIP22ValidationResult(const CValidationState& state)
}
std::string gbt_vb_name(const Consensus::DeploymentPos pos) {
- const struct BIP9DeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos];
+ const struct VBDeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos];
std::string s = vbinfo.name;
if (!vbinfo.gbt_force) {
s.insert(s.begin(), '!');
@@ -318,7 +296,7 @@ std::string gbt_vb_name(const Consensus::DeploymentPos pos) {
UniValue getblocktemplate(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 1)
- throw runtime_error(
+ throw std::runtime_error(
"getblocktemplate ( TemplateRequest )\n"
"\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n"
"It returns data needed to construct a block to work on.\n"
@@ -362,7 +340,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
" n (numeric) transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is\n"
" ,...\n"
" ],\n"
- " \"fee\": n, (numeric) difference in value between transaction inputs and outputs (in Satoshis); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n"
+ " \"fee\": n, (numeric) difference in value between transaction inputs and outputs (in satoshis); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n"
" \"sigops\" : n, (numeric) total SigOps cost, as counted for purposes of block limits; if key is not present, sigop cost is unknown and clients MUST NOT assume it is zero\n"
" \"weight\" : n, (numeric) total transaction weight, as counted for purposes of block limits\n"
" \"required\" : true|false (boolean) if provided and true, this transaction must be in the final block\n"
@@ -372,7 +350,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
" \"coinbaseaux\" : { (json object) data that should be included in the coinbase's scriptSig content\n"
" \"flags\" : \"xx\" (string) key name is to be ignored, and value included in scriptSig\n"
" },\n"
- " \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in Satoshis)\n"
+ " \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in satoshis)\n"
" \"coinbasetxn\" : { ... }, (json object) information for coinbase transaction\n"
" \"target\" : \"xxxx\", (string) The hash target\n"
" \"mintime\" : xxx, (numeric) The minimum timestamp appropriate for next block time in seconds since epoch (Jan 1 1970 GMT)\n"
@@ -400,7 +378,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
UniValue lpval = NullUniValue;
std::set<std::string> setClientRules;
int64_t nMaxVersionPreVB = -1;
- if (request.params.size() > 0)
+ if (!request.params[0].isNull())
{
const UniValue& oparam = request.params[0].get_obj();
const UniValue& modeval = find_value(oparam, "mode");
@@ -519,12 +497,22 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
// TODO: Maybe recheck connections/IBD and (if something wrong) send an expires-immediately template to stop miners?
}
+ const struct VBDeploymentInfo& segwit_info = VersionBitsDeploymentInfo[Consensus::DEPLOYMENT_SEGWIT];
+ // If the caller is indicating segwit support, then allow CreateNewBlock()
+ // to select witness transactions, after segwit activates (otherwise
+ // don't).
+ bool fSupportsSegwit = setClientRules.find(segwit_info.name) != setClientRules.end();
+
// Update block
static CBlockIndex* pindexPrev;
static int64_t nStart;
static std::unique_ptr<CBlockTemplate> pblocktemplate;
+ // Cache whether the last invocation was with segwit support, to avoid returning
+ // a segwit-block to a non-segwit caller.
+ static bool fLastTemplateSupportsSegwit = true;
if (pindexPrev != chainActive.Tip() ||
- (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5))
+ (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5) ||
+ fLastTemplateSupportsSegwit != fSupportsSegwit)
{
// Clear pindexPrev so future calls make a new block, despite any failures from here on
pindexPrev = nullptr;
@@ -533,10 +521,11 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
CBlockIndex* pindexPrevNew = chainActive.Tip();
nStart = GetTime();
+ fLastTemplateSupportsSegwit = fSupportsSegwit;
// Create new block
CScript scriptDummy = CScript() << OP_TRUE;
- pblocktemplate = BlockAssembler(Params()).CreateNewBlock(scriptDummy);
+ pblocktemplate = BlockAssembler(Params()).CreateNewBlock(scriptDummy, fSupportsSegwit);
if (!pblocktemplate)
throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
@@ -556,7 +545,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal");
UniValue transactions(UniValue::VARR);
- map<uint256, int64_t> setTxIndex;
+ std::map<uint256, int64_t> setTxIndex;
int i = 0;
for (const auto& it : pblock->vtx) {
const CTransaction& tx = *it;
@@ -573,7 +562,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
entry.push_back(Pair("hash", tx.GetWitnessHash().GetHex()));
UniValue deps(UniValue::VARR);
- BOOST_FOREACH (const CTxIn &in, tx.vin)
+ for (const CTxIn &in : tx.vin)
{
if (setTxIndex.count(in.prevout.hash))
deps.push_back(setTxIndex[in.prevout.hash]);
@@ -622,7 +611,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
// FALL THROUGH to get vbavailable set...
case THRESHOLD_STARTED:
{
- const struct BIP9DeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos];
+ const struct VBDeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos];
vbavailable.push_back(Pair(gbt_vb_name(pos), consensusParams.vDeployments[pos].bit));
if (setClientRules.find(vbinfo.name) == setClientRules.end()) {
if (!vbinfo.gbt_force) {
@@ -635,7 +624,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
case THRESHOLD_ACTIVE:
{
// Add to rules only
- const struct BIP9DeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos];
+ const struct VBDeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos];
aRules.push_back(gbt_vb_name(pos));
if (setClientRules.find(vbinfo.name) == setClientRules.end()) {
// Not supported by the client; make sure it's safe to proceed
@@ -671,19 +660,23 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
result.push_back(Pair("mutable", aMutable));
result.push_back(Pair("noncerange", "00000000ffffffff"));
int64_t nSigOpLimit = MAX_BLOCK_SIGOPS_COST;
+ int64_t nSizeLimit = MAX_BLOCK_SERIALIZED_SIZE;
if (fPreSegWit) {
assert(nSigOpLimit % WITNESS_SCALE_FACTOR == 0);
nSigOpLimit /= WITNESS_SCALE_FACTOR;
+ assert(nSizeLimit % WITNESS_SCALE_FACTOR == 0);
+ nSizeLimit /= WITNESS_SCALE_FACTOR;
}
result.push_back(Pair("sigoplimit", nSigOpLimit));
- result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SERIALIZED_SIZE));
- result.push_back(Pair("weightlimit", (int64_t)MAX_BLOCK_WEIGHT));
+ result.push_back(Pair("sizelimit", nSizeLimit));
+ if (!fPreSegWit) {
+ result.push_back(Pair("weightlimit", (int64_t)MAX_BLOCK_WEIGHT));
+ }
result.push_back(Pair("curtime", pblock->GetBlockTime()));
result.push_back(Pair("bits", strprintf("%08x", pblock->nBits)));
result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
- const struct BIP9DeploymentInfo& segwit_info = VersionBitsDeploymentInfo[Consensus::DEPLOYMENT_SEGWIT];
- if (!pblocktemplate->vchCoinbaseCommitment.empty() && setClientRules.find(segwit_info.name) != setClientRules.end()) {
+ if (!pblocktemplate->vchCoinbaseCommitment.empty() && fSupportsSegwit) {
result.push_back(Pair("default_witness_commitment", HexStr(pblocktemplate->vchCoinbaseCommitment.begin(), pblocktemplate->vchCoinbaseCommitment.end())));
}
@@ -697,42 +690,45 @@ public:
bool found;
CValidationState state;
- submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {};
+ explicit submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {}
protected:
- virtual void BlockChecked(const CBlock& block, const CValidationState& stateIn) {
+ void BlockChecked(const CBlock& block, const CValidationState& stateIn) override {
if (block.GetHash() != hash)
return;
found = true;
state = stateIn;
- };
+ }
};
UniValue submitblock(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
- "submitblock \"hexdata\" ( \"jsonparametersobject\" )\n"
+ // We allow 2 arguments for compliance with BIP22. Argument 2 is ignored.
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
+ throw std::runtime_error(
+ "submitblock \"hexdata\" ( \"dummy\" )\n"
"\nAttempts to submit new block to network.\n"
- "The 'jsonparametersobject' parameter is currently ignored.\n"
"See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n"
"\nArguments\n"
"1. \"hexdata\" (string, required) the hex-encoded block data to submit\n"
- "2. \"parameters\" (string, optional) object of optional parameters\n"
- " {\n"
- " \"workid\" : \"id\" (string, optional) if the server provided a workid, it MUST be included with submissions\n"
- " }\n"
+ "2. \"dummy\" (optional) dummy value, for compatibility with BIP22. This value is ignored.\n"
"\nResult:\n"
"\nExamples:\n"
+ HelpExampleCli("submitblock", "\"mydata\"")
+ HelpExampleRpc("submitblock", "\"mydata\"")
);
+ }
std::shared_ptr<CBlock> blockptr = std::make_shared<CBlock>();
CBlock& block = *blockptr;
- if (!DecodeHexBlk(block, request.params[0].get_str()))
+ if (!DecodeHexBlk(block, request.params[0].get_str())) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
+ }
+
+ if (block.vtx.empty() || !block.vtx[0]->IsCoinBase()) {
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block does not start with a coinbase");
+ }
uint256 hash = block.GetHash();
bool fBlockPresent = false;
@@ -741,10 +737,12 @@ UniValue submitblock(const JSONRPCRequest& request)
BlockMap::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end()) {
CBlockIndex *pindex = mi->second;
- if (pindex->IsValid(BLOCK_VALID_SCRIPTS))
+ if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) {
return "duplicate";
- if (pindex->nStatus & BLOCK_FAILED_MASK)
+ }
+ if (pindex->nStatus & BLOCK_FAILED_MASK) {
return "duplicate-invalid";
+ }
// Otherwise, we might only have the header - process the block before returning
fBlockPresent = true;
}
@@ -760,24 +758,26 @@ UniValue submitblock(const JSONRPCRequest& request)
submitblock_StateCatcher sc(block.GetHash());
RegisterValidationInterface(&sc);
- bool fAccepted = ProcessNewBlock(Params(), blockptr, true, NULL);
+ bool fAccepted = ProcessNewBlock(Params(), blockptr, true, nullptr);
UnregisterValidationInterface(&sc);
- if (fBlockPresent)
- {
- if (fAccepted && !sc.found)
+ if (fBlockPresent) {
+ if (fAccepted && !sc.found) {
return "duplicate-inconclusive";
+ }
return "duplicate";
}
- if (!sc.found)
+ if (!sc.found) {
return "inconclusive";
+ }
return BIP22ValidationResult(sc.state);
}
UniValue estimatefee(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"estimatefee nblocks\n"
+ "\nDEPRECATED. Please use estimatesmartfee for more intelligent estimates."
"\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
"confirmation within nblocks blocks. Uses virtual transaction size of transaction\n"
"as defined in BIP 141 (witness data is discounted).\n"
@@ -794,135 +794,204 @@ UniValue estimatefee(const JSONRPCRequest& request)
+ HelpExampleCli("estimatefee", "6")
);
- RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));
+ if (!IsDeprecatedRPCEnabled("estimatefee")) {
+ throw JSONRPCError(RPC_METHOD_DEPRECATED, "estimatefee is deprecated and will be fully removed in v0.17. "
+ "To use estimatefee in v0.16, restart bitcoind with -deprecatedrpc=estimatefee.\n"
+ "Projects should transition to using estimatesmartfee before upgrading to v0.17");
+ }
+
+ RPCTypeCheck(request.params, {UniValue::VNUM});
int nBlocks = request.params[0].get_int();
if (nBlocks < 1)
nBlocks = 1;
- CFeeRate feeRate = mempool.estimateFee(nBlocks);
+ CFeeRate feeRate = ::feeEstimator.estimateFee(nBlocks);
if (feeRate == CFeeRate(0))
return -1.0;
return ValueFromAmount(feeRate.GetFeePerK());
}
-UniValue estimatepriority(const JSONRPCRequest& request)
-{
- if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
- "estimatepriority nblocks\n"
- "\nDEPRECATED. Estimates the approximate priority a zero-fee transaction needs to begin\n"
- "confirmation within nblocks blocks.\n"
- "\nArguments:\n"
- "1. nblocks (numeric, required)\n"
- "\nResult:\n"
- "n (numeric) estimated priority\n"
- "\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(request.params, boost::assign::list_of(UniValue::VNUM));
-
- int nBlocks = request.params[0].get_int();
- if (nBlocks < 1)
- nBlocks = 1;
-
- return mempool.estimatePriority(nBlocks);
-}
-
UniValue estimatesmartfee(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
- "estimatesmartfee nblocks\n"
- "\nWARNING: This interface is unstable and may disappear or change!\n"
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
+ throw std::runtime_error(
+ "estimatesmartfee conf_target (\"estimate_mode\")\n"
"\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
- "confirmation within nblocks blocks if possible and return the number of blocks\n"
+ "confirmation within conf_target blocks if possible and return the number of blocks\n"
"for which the estimate is valid. Uses virtual transaction size as defined\n"
"in BIP 141 (witness data is discounted).\n"
"\nArguments:\n"
- "1. nblocks (numeric)\n"
+ "1. conf_target (numeric) Confirmation target in blocks (1 - 1008)\n"
+ "2. \"estimate_mode\" (string, optional, default=CONSERVATIVE) The fee estimate mode.\n"
+ " Whether to return a more conservative estimate which also satisfies\n"
+ " a longer history. A conservative estimate potentially returns a\n"
+ " higher feerate and is more likely to be sufficient for the desired\n"
+ " target, but is not as responsive to short term drops in the\n"
+ " prevailing fee market. Must be one of:\n"
+ " \"UNSET\" (defaults to CONSERVATIVE)\n"
+ " \"ECONOMICAL\"\n"
+ " \"CONSERVATIVE\"\n"
"\nResult:\n"
"{\n"
- " \"feerate\" : x.x, (numeric) estimate fee-per-kilobyte (in BTC)\n"
+ " \"feerate\" : x.x, (numeric, optional) estimate fee rate in " + CURRENCY_UNIT + "/kB\n"
+ " \"errors\": [ str... ] (json array of strings, optional) Errors encountered during processing\n"
" \"blocks\" : n (numeric) block number where estimate was found\n"
"}\n"
"\n"
- "A negative value is returned if not enough transactions and blocks\n"
+ "The request target will be clamped between 2 and the highest target\n"
+ "fee estimation is able to return based on how long it has been running.\n"
+ "An error is returned if not enough transactions and blocks\n"
"have been observed to make an estimate for any number of blocks.\n"
- "However it will not return a value below the mempool reject fee.\n"
"\nExample:\n"
+ HelpExampleCli("estimatesmartfee", "6")
);
- RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));
-
- int nBlocks = request.params[0].get_int();
+ RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VSTR});
+ RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
+ unsigned int conf_target = ParseConfirmTarget(request.params[0]);
+ bool conservative = true;
+ if (!request.params[1].isNull()) {
+ FeeEstimateMode fee_mode;
+ if (!FeeModeFromString(request.params[1].get_str(), fee_mode)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
+ }
+ if (fee_mode == FeeEstimateMode::ECONOMICAL) conservative = false;
+ }
UniValue result(UniValue::VOBJ);
- int answerFound;
- CFeeRate feeRate = mempool.estimateSmartFee(nBlocks, &answerFound);
- result.push_back(Pair("feerate", feeRate == CFeeRate(0) ? -1.0 : ValueFromAmount(feeRate.GetFeePerK())));
- result.push_back(Pair("blocks", answerFound));
+ UniValue errors(UniValue::VARR);
+ FeeCalculation feeCalc;
+ CFeeRate feeRate = ::feeEstimator.estimateSmartFee(conf_target, &feeCalc, conservative);
+ if (feeRate != CFeeRate(0)) {
+ result.push_back(Pair("feerate", ValueFromAmount(feeRate.GetFeePerK())));
+ } else {
+ errors.push_back("Insufficient data or no feerate found");
+ result.push_back(Pair("errors", errors));
+ }
+ result.push_back(Pair("blocks", feeCalc.returnedTarget));
return result;
}
-UniValue estimatesmartpriority(const JSONRPCRequest& request)
+UniValue estimaterawfee(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
- "estimatesmartpriority nblocks\n"
- "\nDEPRECATED. WARNING: This interface is unstable and may disappear or change!\n"
- "\nEstimates the approximate priority a zero-fee transaction needs to begin\n"
- "confirmation within nblocks blocks if possible and return the number of blocks\n"
- "for which the estimate is valid.\n"
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
+ throw std::runtime_error(
+ "estimaterawfee conf_target (threshold)\n"
+ "\nWARNING: This interface is unstable and may disappear or change!\n"
+ "\nWARNING: This is an advanced API call that is tightly coupled to the specific\n"
+ " implementation of fee estimation. The parameters it can be called with\n"
+ " and the results it returns will change if the internal implementation changes.\n"
+ "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
+ "confirmation within conf_target blocks if possible. Uses virtual transaction size as\n"
+ "defined in BIP 141 (witness data is discounted).\n"
"\nArguments:\n"
- "1. nblocks (numeric, required)\n"
+ "1. conf_target (numeric) Confirmation target in blocks (1 - 1008)\n"
+ "2. threshold (numeric, optional) The proportion of transactions in a given feerate range that must have been\n"
+ " confirmed within conf_target in order to consider those feerates as high enough and proceed to check\n"
+ " lower buckets. Default: 0.95\n"
"\nResult:\n"
"{\n"
- " \"priority\" : x.x, (numeric) estimated priority\n"
- " \"blocks\" : n (numeric) block number where estimate was found\n"
+ " \"short\" : { (json object, optional) estimate for short time horizon\n"
+ " \"feerate\" : x.x, (numeric, optional) estimate fee rate in " + CURRENCY_UNIT + "/kB\n"
+ " \"decay\" : x.x, (numeric) exponential decay (per block) for historical moving average of confirmation data\n"
+ " \"scale\" : x, (numeric) The resolution of confirmation targets at this time horizon\n"
+ " \"pass\" : { (json object, optional) information about the lowest range of feerates to succeed in meeting the threshold\n"
+ " \"startrange\" : x.x, (numeric) start of feerate range\n"
+ " \"endrange\" : x.x, (numeric) end of feerate range\n"
+ " \"withintarget\" : x.x, (numeric) number of txs over history horizon in the feerate range that were confirmed within target\n"
+ " \"totalconfirmed\" : x.x, (numeric) number of txs over history horizon in the feerate range that were confirmed at any point\n"
+ " \"inmempool\" : x.x, (numeric) current number of txs in mempool in the feerate range unconfirmed for at least target blocks\n"
+ " \"leftmempool\" : x.x, (numeric) number of txs over history horizon in the feerate range that left mempool unconfirmed after target\n"
+ " },\n"
+ " \"fail\" : { ... }, (json object, optional) information about the highest range of feerates to fail to meet the threshold\n"
+ " \"errors\": [ str... ] (json array of strings, optional) Errors encountered during processing\n"
+ " },\n"
+ " \"medium\" : { ... }, (json object, optional) estimate for medium time horizon\n"
+ " \"long\" : { ... } (json object) estimate for long time horizon\n"
"}\n"
"\n"
- "A negative value is returned if not enough transactions and blocks\n"
- "have been observed to make an estimate for any number of blocks.\n"
- "However if the mempool reject fee is set it will return 1e9 * MAX_MONEY.\n"
+ "Results are returned for any horizon which tracks blocks up to the confirmation target.\n"
"\nExample:\n"
- + HelpExampleCli("estimatesmartpriority", "6")
+ + HelpExampleCli("estimaterawfee", "6 0.9")
);
- RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));
-
- int nBlocks = request.params[0].get_int();
+ RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM}, true);
+ RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
+ unsigned int conf_target = ParseConfirmTarget(request.params[0]);
+ double threshold = 0.95;
+ if (!request.params[1].isNull()) {
+ threshold = request.params[1].get_real();
+ }
+ if (threshold < 0 || threshold > 1) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid threshold");
+ }
UniValue result(UniValue::VOBJ);
- int answerFound;
- double priority = mempool.estimateSmartPriority(nBlocks, &answerFound);
- result.push_back(Pair("priority", priority));
- result.push_back(Pair("blocks", answerFound));
+
+ for (FeeEstimateHorizon horizon : {FeeEstimateHorizon::SHORT_HALFLIFE, FeeEstimateHorizon::MED_HALFLIFE, FeeEstimateHorizon::LONG_HALFLIFE}) {
+ CFeeRate feeRate;
+ EstimationResult buckets;
+
+ // Only output results for horizons which track the target
+ if (conf_target > ::feeEstimator.HighestTargetTracked(horizon)) continue;
+
+ feeRate = ::feeEstimator.estimateRawFee(conf_target, threshold, horizon, &buckets);
+ UniValue horizon_result(UniValue::VOBJ);
+ UniValue errors(UniValue::VARR);
+ UniValue passbucket(UniValue::VOBJ);
+ passbucket.push_back(Pair("startrange", round(buckets.pass.start)));
+ passbucket.push_back(Pair("endrange", round(buckets.pass.end)));
+ passbucket.push_back(Pair("withintarget", round(buckets.pass.withinTarget * 100.0) / 100.0));
+ passbucket.push_back(Pair("totalconfirmed", round(buckets.pass.totalConfirmed * 100.0) / 100.0));
+ passbucket.push_back(Pair("inmempool", round(buckets.pass.inMempool * 100.0) / 100.0));
+ passbucket.push_back(Pair("leftmempool", round(buckets.pass.leftMempool * 100.0) / 100.0));
+ UniValue failbucket(UniValue::VOBJ);
+ failbucket.push_back(Pair("startrange", round(buckets.fail.start)));
+ failbucket.push_back(Pair("endrange", round(buckets.fail.end)));
+ failbucket.push_back(Pair("withintarget", round(buckets.fail.withinTarget * 100.0) / 100.0));
+ failbucket.push_back(Pair("totalconfirmed", round(buckets.fail.totalConfirmed * 100.0) / 100.0));
+ failbucket.push_back(Pair("inmempool", round(buckets.fail.inMempool * 100.0) / 100.0));
+ failbucket.push_back(Pair("leftmempool", round(buckets.fail.leftMempool * 100.0) / 100.0));
+
+ // CFeeRate(0) is used to indicate error as a return value from estimateRawFee
+ if (feeRate != CFeeRate(0)) {
+ horizon_result.push_back(Pair("feerate", ValueFromAmount(feeRate.GetFeePerK())));
+ horizon_result.push_back(Pair("decay", buckets.decay));
+ horizon_result.push_back(Pair("scale", (int)buckets.scale));
+ horizon_result.push_back(Pair("pass", passbucket));
+ // buckets.fail.start == -1 indicates that all buckets passed, there is no fail bucket to output
+ if (buckets.fail.start != -1) horizon_result.push_back(Pair("fail", failbucket));
+ } else {
+ // Output only information that is still meaningful in the event of error
+ horizon_result.push_back(Pair("decay", buckets.decay));
+ horizon_result.push_back(Pair("scale", (int)buckets.scale));
+ horizon_result.push_back(Pair("fail", failbucket));
+ errors.push_back("Insufficient data or no feerate found which meets threshold");
+ horizon_result.push_back(Pair("errors",errors));
+ }
+ result.push_back(Pair(StringForFeeEstimateHorizon(horizon), horizon_result));
+ }
return result;
}
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafeMode
+{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
- { "mining", "getnetworkhashps", &getnetworkhashps, true, {"nblocks","height"} },
- { "mining", "getmininginfo", &getmininginfo, true, {} },
- { "mining", "prioritisetransaction", &prioritisetransaction, true, {"txid","priority_delta","fee_delta"} },
- { "mining", "getblocktemplate", &getblocktemplate, true, {"template_request"} },
- { "mining", "submitblock", &submitblock, true, {"hexdata","parameters"} },
-
- { "generating", "generate", &generate, true, {"nblocks","maxtries"} },
- { "generating", "generatetoaddress", &generatetoaddress, true, {"nblocks","address","maxtries"} },
-
- { "util", "estimatefee", &estimatefee, true, {"nblocks"} },
- { "util", "estimatepriority", &estimatepriority, true, {"nblocks"} },
- { "util", "estimatesmartfee", &estimatesmartfee, true, {"nblocks"} },
- { "util", "estimatesmartpriority", &estimatesmartpriority, true, {"nblocks"} },
+ { "mining", "getnetworkhashps", &getnetworkhashps, {"nblocks","height"} },
+ { "mining", "getmininginfo", &getmininginfo, {} },
+ { "mining", "prioritisetransaction", &prioritisetransaction, {"txid","dummy","fee_delta"} },
+ { "mining", "getblocktemplate", &getblocktemplate, {"template_request"} },
+ { "mining", "submitblock", &submitblock, {"hexdata","dummy"} },
+
+
+ { "generating", "generatetoaddress", &generatetoaddress, {"nblocks","address","maxtries"} },
+
+ { "util", "estimatefee", &estimatefee, {"nblocks"} },
+ { "util", "estimatesmartfee", &estimatesmartfee, {"conf_target", "estimate_mode"} },
+
+ { "hidden", "estimaterawfee", &estimaterawfee, {"conf_target", "threshold"} },
};
void RegisterMiningRPCCommands(CRPCTable &t)
diff --git a/src/rpc/mining.h b/src/rpc/mining.h
new file mode 100644
index 0000000000..868d7002b5
--- /dev/null
+++ b/src/rpc/mining.h
@@ -0,0 +1,18 @@
+// Copyright (c) 2017 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_RPC_MINING_H
+#define BITCOIN_RPC_MINING_H
+
+#include "script/script.h"
+
+#include <univalue.h>
+
+/** Generate blocks (mine) */
+UniValue generateBlocks(std::shared_ptr<CReserveScript> coinbaseScript, int nGenerate, uint64_t nMaxTries, bool keepScript);
+
+/** Check bounds on a command line confirm target */
+unsigned int ParseConfirmTarget(const UniValue& value);
+
+#endif
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 54d8c3e035..521b49e2a7 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -4,121 +4,50 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "base58.h"
+#include "chain.h"
#include "clientversion.h"
+#include "core_io.h"
+#include "crypto/ripemd160.h"
#include "init.h"
#include "validation.h"
+#include "httpserver.h"
#include "net.h"
#include "netbase.h"
+#include "rpc/blockchain.h"
#include "rpc/server.h"
#include "timedata.h"
#include "util.h"
#include "utilstrencodings.h"
#ifdef ENABLE_WALLET
+#include "wallet/rpcwallet.h"
#include "wallet/wallet.h"
#include "wallet/walletdb.h"
#endif
+#include "warnings.h"
#include <stdint.h>
-
-#include <boost/assign/list_of.hpp>
-
-#include <univalue.h>
-
-using namespace std;
-
-/**
- * @note Do not add or change anything in the information returned by this
- * method. `getinfo` exists for backwards-compatibility only. It combines
- * information from wildly different sources in the program, which is a mess,
- * and is thus planned to be deprecated eventually.
- *
- * Based on the source of the information, new information should be added to:
- * - `getblockchaininfo`,
- * - `getnetworkinfo` or
- * - `getwalletinfo`
- *
- * Or alternatively, create a specific query method for the information.
- **/
-UniValue getinfo(const JSONRPCRequest& request)
-{
- if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
- "getinfo\n"
- "\nDEPRECATED. Returns an object containing various state info.\n"
- "\nResult:\n"
- "{\n"
- " \"version\": xxxxx, (numeric) the server version\n"
- " \"protocolversion\": xxxxx, (numeric) the protocol version\n"
- " \"walletversion\": xxxxx, (numeric) the wallet version\n"
- " \"balance\": xxxxxxx, (numeric) the total bitcoin balance of the wallet\n"
- " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n"
- " \"timeoffset\": xxxxx, (numeric) the time offset\n"
- " \"connections\": xxxxx, (numeric) the number of connections\n"
- " \"proxy\": \"host:port\", (string, optional) the proxy used by the server\n"
- " \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
- " \"testnet\": true|false, (boolean) if the server is using testnet or not\n"
- " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since Unix 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 " + 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"
- + HelpExampleCli("getinfo", "")
- + HelpExampleRpc("getinfo", "")
- );
-
-#ifdef ENABLE_WALLET
- LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
-#else
- LOCK(cs_main);
+#ifdef HAVE_MALLOC_INFO
+#include <malloc.h>
#endif
- proxyType proxy;
- GetProxy(NET_IPV4, proxy);
-
- UniValue obj(UniValue::VOBJ);
- obj.push_back(Pair("version", CLIENT_VERSION));
- obj.push_back(Pair("protocolversion", PROTOCOL_VERSION));
-#ifdef ENABLE_WALLET
- if (pwalletMain) {
- obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
- obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
- }
-#endif
- obj.push_back(Pair("blocks", (int)chainActive.Height()));
- obj.push_back(Pair("timeoffset", GetTimeOffset()));
- if(g_connman)
- obj.push_back(Pair("connections", (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL)));
- obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string())));
- obj.push_back(Pair("difficulty", (double)GetDifficulty()));
- obj.push_back(Pair("testnet", Params().NetworkIDString() == CBaseChainParams::TESTNET));
-#ifdef ENABLE_WALLET
- if (pwalletMain) {
- obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
- obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
- }
- if (pwalletMain && pwalletMain->IsCrypted())
- obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
- obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
-#endif
- obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())));
- obj.push_back(Pair("errors", GetWarnings("statusbar")));
- return obj;
-}
+#include <univalue.h>
#ifdef ENABLE_WALLET
class DescribeAddressVisitor : public boost::static_visitor<UniValue>
{
public:
+ CWallet * const pwallet;
+
+ explicit DescribeAddressVisitor(CWallet *_pwallet) : pwallet(_pwallet) {}
+
UniValue operator()(const CNoDestination &dest) const { return UniValue(UniValue::VOBJ); }
UniValue operator()(const CKeyID &keyID) const {
UniValue obj(UniValue::VOBJ);
CPubKey vchPubKey;
obj.push_back(Pair("isscript", false));
- if (pwalletMain && pwalletMain->GetPubKey(keyID, vchPubKey)) {
+ obj.push_back(Pair("iswitness", false));
+ if (pwallet && pwallet->GetPubKey(keyID, vchPubKey)) {
obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
}
@@ -129,7 +58,8 @@ public:
UniValue obj(UniValue::VOBJ);
CScript subscript;
obj.push_back(Pair("isscript", true));
- if (pwalletMain && pwalletMain->GetCScript(scriptID, subscript)) {
+ obj.push_back(Pair("iswitness", false));
+ if (pwallet && pwallet->GetCScript(scriptID, subscript)) {
std::vector<CTxDestination> addresses;
txnouttype whichType;
int nRequired;
@@ -137,21 +67,63 @@ public:
obj.push_back(Pair("script", GetTxnOutputType(whichType)));
obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
UniValue a(UniValue::VARR);
- BOOST_FOREACH(const CTxDestination& addr, addresses)
- a.push_back(CBitcoinAddress(addr).ToString());
+ for (const CTxDestination& addr : addresses) {
+ a.push_back(EncodeDestination(addr));
+ }
obj.push_back(Pair("addresses", a));
if (whichType == TX_MULTISIG)
obj.push_back(Pair("sigsrequired", nRequired));
}
return obj;
}
+
+ UniValue operator()(const WitnessV0KeyHash& id) const
+ {
+ UniValue obj(UniValue::VOBJ);
+ CPubKey pubkey;
+ obj.push_back(Pair("isscript", false));
+ obj.push_back(Pair("iswitness", true));
+ obj.push_back(Pair("witness_version", 0));
+ obj.push_back(Pair("witness_program", HexStr(id.begin(), id.end())));
+ if (pwallet && pwallet->GetPubKey(CKeyID(id), pubkey)) {
+ obj.push_back(Pair("pubkey", HexStr(pubkey)));
+ }
+ return obj;
+ }
+
+ UniValue operator()(const WitnessV0ScriptHash& id) const
+ {
+ UniValue obj(UniValue::VOBJ);
+ CScript subscript;
+ obj.push_back(Pair("isscript", true));
+ obj.push_back(Pair("iswitness", true));
+ obj.push_back(Pair("witness_version", 0));
+ obj.push_back(Pair("witness_program", HexStr(id.begin(), id.end())));
+ CRIPEMD160 hasher;
+ uint160 hash;
+ hasher.Write(id.begin(), 32).Finalize(hash.begin());
+ if (pwallet && pwallet->GetCScript(CScriptID(hash), subscript)) {
+ obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
+ }
+ return obj;
+ }
+
+ UniValue operator()(const WitnessUnknown& id) const
+ {
+ UniValue obj(UniValue::VOBJ);
+ CScript subscript;
+ obj.push_back(Pair("iswitness", true));
+ obj.push_back(Pair("witness_version", (int)id.version));
+ obj.push_back(Pair("witness_program", HexStr(id.program, id.program + id.length)));
+ return obj;
+ }
};
#endif
UniValue validateaddress(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"validateaddress \"address\"\n"
"\nReturn information about the given bitcoin address.\n"
"\nArguments:\n"
@@ -164,9 +136,18 @@ UniValue validateaddress(const JSONRPCRequest& request)
" \"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"
+ " \"script\" : \"type\" (string, optional) The output script type. Possible types: nonstandard, pubkey, pubkeyhash, scripthash, multisig, nulldata, witness_v0_keyhash, witness_v0_scripthash\n"
+ " \"hex\" : \"hex\", (string, optional) The redeemscript for the p2sh address\n"
+ " \"addresses\" (string, optional) Array of addresses associated with the known redeemscript\n"
+ " [\n"
+ " \"address\"\n"
+ " ,...\n"
+ " ]\n"
+ " \"sigsrequired\" : xxxxx (numeric, optional) Number of signatures required to spend multisig output\n"
" \"pubkey\" : \"publickeyhex\", (string) The hex value of the raw public key\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"
+ " \"timestamp\" : timestamp, (number, optional) The creation time of the key if available in seconds since epoch (Jan 1 1970 GMT)\n"
" \"hdkeypath\" : \"keypath\" (string, optional) The HD keypath if the key is HD and available\n"
" \"hdmasterkeyid\" : \"<hash160>\" (string, optional) The Hash160 of the HD master pubkey\n"
"}\n"
@@ -176,61 +157,75 @@ UniValue validateaddress(const JSONRPCRequest& request)
);
#ifdef ENABLE_WALLET
- LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+
+ LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : nullptr);
#else
LOCK(cs_main);
#endif
- CBitcoinAddress address(request.params[0].get_str());
- bool isValid = address.IsValid();
+ CTxDestination dest = DecodeDestination(request.params[0].get_str());
+ bool isValid = IsValidDestination(dest);
UniValue ret(UniValue::VOBJ);
ret.push_back(Pair("isvalid", isValid));
if (isValid)
{
- CTxDestination dest = address.Get();
- string currentAddress = address.ToString();
+ std::string currentAddress = EncodeDestination(dest);
ret.push_back(Pair("address", currentAddress));
CScript scriptPubKey = GetScriptForDestination(dest);
ret.push_back(Pair("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
#ifdef ENABLE_WALLET
- isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : ISMINE_NO;
- ret.push_back(Pair("ismine", (mine & ISMINE_SPENDABLE) ? true : false));
- ret.push_back(Pair("iswatchonly", (mine & ISMINE_WATCH_ONLY) ? true: false));
- UniValue detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
+ isminetype mine = pwallet ? IsMine(*pwallet, dest) : ISMINE_NO;
+ ret.push_back(Pair("ismine", bool(mine & ISMINE_SPENDABLE)));
+ ret.push_back(Pair("iswatchonly", bool(mine & ISMINE_WATCH_ONLY)));
+ UniValue detail = boost::apply_visitor(DescribeAddressVisitor(pwallet), dest);
ret.pushKVs(detail);
- if (pwalletMain && pwalletMain->mapAddressBook.count(dest))
- ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name));
- CKeyID keyID;
- if (pwalletMain && address.GetKeyID(keyID) && pwalletMain->mapKeyMetadata.count(keyID) && !pwalletMain->mapKeyMetadata[keyID].hdKeypath.empty())
- {
- ret.push_back(Pair("hdkeypath", pwalletMain->mapKeyMetadata[keyID].hdKeypath));
- ret.push_back(Pair("hdmasterkeyid", pwalletMain->mapKeyMetadata[keyID].hdMasterKeyID.GetHex()));
+ if (pwallet && pwallet->mapAddressBook.count(dest)) {
+ ret.push_back(Pair("account", pwallet->mapAddressBook[dest].name));
+ }
+ if (pwallet) {
+ const auto& meta = pwallet->mapKeyMetadata;
+ const CKeyID *keyID = boost::get<CKeyID>(&dest);
+ auto it = keyID ? meta.find(*keyID) : meta.end();
+ if (it == meta.end()) {
+ it = meta.find(CScriptID(scriptPubKey));
+ }
+ if (it != meta.end()) {
+ ret.push_back(Pair("timestamp", it->second.nCreateTime));
+ if (!it->second.hdKeypath.empty()) {
+ ret.push_back(Pair("hdkeypath", it->second.hdKeypath));
+ ret.push_back(Pair("hdmasterkeyid", it->second.hdMasterKeyID.GetHex()));
+ }
+ }
}
#endif
}
return ret;
}
+// Needed even with !ENABLE_WALLET, to pass (ignored) pointers around
+class CWallet;
+
/**
* Used by addmultisigaddress / createmultisig:
*/
-CScript _createmultisig_redeemScript(const UniValue& params)
+CScript _createmultisig_redeemScript(CWallet * const pwallet, const UniValue& params)
{
int nRequired = params[0].get_int();
const UniValue& keys = params[1].get_array();
// Gather public keys
if (nRequired < 1)
- throw runtime_error("a multisignature address must require at least one key to redeem");
+ throw std::runtime_error("a multisignature address must require at least one key to redeem");
if ((int)keys.size() < nRequired)
- throw runtime_error(
+ throw std::runtime_error(
strprintf("not enough keys supplied "
"(got %u keys, but need at least %d to redeem)", keys.size(), nRequired));
if (keys.size() > 16)
- throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
+ throw std::runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
std::vector<CPubKey> pubkeys;
pubkeys.resize(keys.size());
for (unsigned int i = 0; i < keys.size(); i++)
@@ -238,19 +233,18 @@ CScript _createmultisig_redeemScript(const UniValue& params)
const std::string& ks = keys[i].get_str();
#ifdef ENABLE_WALLET
// Case 1: Bitcoin address and we have full public key:
- CBitcoinAddress address(ks);
- if (pwalletMain && address.IsValid())
- {
- CKeyID keyID;
- if (!address.GetKeyID(keyID))
- throw runtime_error(
- strprintf("%s does not refer to a key",ks));
+ CTxDestination dest = DecodeDestination(ks);
+ if (pwallet && IsValidDestination(dest)) {
+ const CKeyID *keyID = boost::get<CKeyID>(&dest);
+ if (!keyID) {
+ throw std::runtime_error(strprintf("%s does not refer to a key", ks));
+ }
CPubKey vchPubKey;
- if (!pwalletMain->GetPubKey(keyID, vchPubKey))
- throw runtime_error(
- strprintf("no full public key for address %s",ks));
+ if (!pwallet->GetPubKey(*keyID, vchPubKey)) {
+ throw std::runtime_error(strprintf("no full public key for address %s", ks));
+ }
if (!vchPubKey.IsFullyValid())
- throw runtime_error(" Invalid public key: "+ks);
+ throw std::runtime_error(" Invalid public key: "+ks);
pubkeys[i] = vchPubKey;
}
@@ -261,18 +255,18 @@ CScript _createmultisig_redeemScript(const UniValue& params)
{
CPubKey vchPubKey(ParseHex(ks));
if (!vchPubKey.IsFullyValid())
- throw runtime_error(" Invalid public key: "+ks);
+ throw std::runtime_error(" Invalid public key: "+ks);
pubkeys[i] = vchPubKey;
}
else
{
- throw runtime_error(" Invalid public key: "+ks);
+ throw std::runtime_error(" Invalid public key: "+ks);
}
}
CScript result = GetScriptForMultisig(nRequired, pubkeys);
if (result.size() > MAX_SCRIPT_ELEMENT_SIZE)
- throw runtime_error(
+ throw std::runtime_error(
strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE));
return result;
@@ -280,9 +274,15 @@ CScript _createmultisig_redeemScript(const UniValue& params)
UniValue createmultisig(const JSONRPCRequest& request)
{
+#ifdef ENABLE_WALLET
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+#else
+ CWallet * const pwallet = nullptr;
+#endif
+
if (request.fHelp || request.params.size() < 2 || request.params.size() > 2)
{
- string msg = "createmultisig nrequired [\"key\",...]\n"
+ std::string msg = "createmultisig nrequired [\"key\",...]\n"
"\nCreates a multi-signature address with n signature of m keys required.\n"
"It returns a json object with the address and redeemScript.\n"
@@ -306,16 +306,15 @@ UniValue createmultisig(const JSONRPCRequest& request)
"\nAs a json rpc call\n"
+ HelpExampleRpc("createmultisig", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
;
- throw runtime_error(msg);
+ throw std::runtime_error(msg);
}
// Construct using pay-to-script-hash:
- CScript inner = _createmultisig_redeemScript(request.params);
+ CScript inner = _createmultisig_redeemScript(pwallet, request.params);
CScriptID innerID(inner);
- CBitcoinAddress address(innerID);
UniValue result(UniValue::VOBJ);
- result.push_back(Pair("address", address.ToString()));
+ result.push_back(Pair("address", EncodeDestination(innerID)));
result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));
return result;
@@ -324,7 +323,7 @@ UniValue createmultisig(const JSONRPCRequest& request)
UniValue verifymessage(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 3)
- throw runtime_error(
+ throw std::runtime_error(
"verifymessage \"address\" \"signature\" \"message\"\n"
"\nVerify a signed message\n"
"\nArguments:\n"
@@ -337,29 +336,31 @@ UniValue verifymessage(const JSONRPCRequest& request)
"\nUnlock the wallet for 30 seconds\n"
+ HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
"\nCreate the signature\n"
- + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"my message\"") +
+ + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") +
"\nVerify the signature\n"
- + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") +
+ + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
"\nAs json rpc\n"
- + HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"signature\", \"my message\"")
+ + HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"signature\", \"my message\"")
);
LOCK(cs_main);
- string strAddress = request.params[0].get_str();
- string strSign = request.params[1].get_str();
- string strMessage = request.params[2].get_str();
+ std::string strAddress = request.params[0].get_str();
+ std::string strSign = request.params[1].get_str();
+ std::string strMessage = request.params[2].get_str();
- CBitcoinAddress addr(strAddress);
- if (!addr.IsValid())
+ CTxDestination destination = DecodeDestination(strAddress);
+ if (!IsValidDestination(destination)) {
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
+ }
- CKeyID keyID;
- if (!addr.GetKeyID(keyID))
+ const CKeyID *keyID = boost::get<CKeyID>(&destination);
+ if (!keyID) {
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
+ }
bool fInvalid = false;
- vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
+ std::vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
if (fInvalid)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
@@ -372,13 +373,13 @@ UniValue verifymessage(const JSONRPCRequest& request)
if (!pubkey.RecoverCompact(ss.GetHash(), vchSig))
return false;
- return (pubkey.GetID() == keyID);
+ return (pubkey.GetID() == *keyID);
}
UniValue signmessagewithprivkey(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 2)
- throw runtime_error(
+ throw std::runtime_error(
"signmessagewithprivkey \"privkey\" \"message\"\n"
"\nSign a message with the private key of an address\n"
"\nArguments:\n"
@@ -390,13 +391,13 @@ UniValue signmessagewithprivkey(const JSONRPCRequest& request)
"\nCreate the signature\n"
+ HelpExampleCli("signmessagewithprivkey", "\"privkey\" \"my message\"") +
"\nVerify the signature\n"
- + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") +
+ + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
"\nAs json rpc\n"
+ HelpExampleRpc("signmessagewithprivkey", "\"privkey\", \"my message\"")
);
- string strPrivkey = request.params[0].get_str();
- string strMessage = request.params[1].get_str();
+ std::string strPrivkey = request.params[0].get_str();
+ std::string strMessage = request.params[1].get_str();
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(strPrivkey);
@@ -410,17 +411,17 @@ UniValue signmessagewithprivkey(const JSONRPCRequest& request)
ss << strMessageMagic;
ss << strMessage;
- vector<unsigned char> vchSig;
+ std::vector<unsigned char> vchSig;
if (!key.SignCompact(ss.GetHash(), vchSig))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
- return EncodeBase64(&vchSig[0], vchSig.size());
+ return EncodeBase64(vchSig.data(), vchSig.size());
}
UniValue setmocktime(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"setmocktime timestamp\n"
"\nSet the local time to given timestamp (-regtest only)\n"
"\nArguments:\n"
@@ -429,24 +430,18 @@ UniValue setmocktime(const JSONRPCRequest& request)
);
if (!Params().MineBlocksOnDemand())
- throw runtime_error("setmocktime for regression testing (-regtest mode) only");
+ throw std::runtime_error("setmocktime for regression testing (-regtest mode) only");
- // 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.
+ // For now, don't change mocktime if we're in the middle of validation, as
+ // this could have an effect on mempool time-based eviction, as well as
+ // IsCurrentForFeeEstimation() and IsInitialBlockDownload().
+ // TODO: figure out the right way to synchronize around mocktime, and
+ // ensure all call sites of GetTime() are accessing this safely.
LOCK(cs_main);
- RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));
+ RPCTypeCheck(request.params, {UniValue::VNUM});
SetMockTime(request.params[0].get_int64());
- uint64_t t = GetTime();
- if(g_connman) {
- g_connman->ForEachNode([t](CNode* pnode) {
- pnode->nLastSend = pnode->nLastRecv = t;
- });
- }
-
return NullUniValue;
}
@@ -463,16 +458,39 @@ static UniValue RPCLockedMemoryInfo()
return obj;
}
+#ifdef HAVE_MALLOC_INFO
+static std::string RPCMallocInfo()
+{
+ char *ptr = nullptr;
+ size_t size = 0;
+ FILE *f = open_memstream(&ptr, &size);
+ if (f) {
+ malloc_info(0, f);
+ fclose(f);
+ if (ptr) {
+ std::string rv(ptr, size);
+ free(ptr);
+ return rv;
+ }
+ }
+ return "";
+}
+#endif
+
UniValue getmemoryinfo(const JSONRPCRequest& request)
{
/* Please, avoid using the word "pool" here in the RPC interface or help,
* as users will undoubtedly confuse it with the other "memory pool"
*/
- if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
- "getmemoryinfo\n"
+ if (request.fHelp || request.params.size() > 1)
+ throw std::runtime_error(
+ "getmemoryinfo (\"mode\")\n"
"Returns an object containing information about memory usage.\n"
- "\nResult:\n"
+ "Arguments:\n"
+ "1. \"mode\" determines what kind of information is returned. This argument is optional, the default mode is \"stats\".\n"
+ " - \"stats\" returns general statistics about memory usage in the daemon.\n"
+ " - \"mallocinfo\" returns an XML string describing low-level heap state (only available if compiled with glibc 2.10+).\n"
+ "\nResult (mode \"stats\"):\n"
"{\n"
" \"locked\": { (json object) Information about locked memory manager\n"
" \"used\": xxxxx, (numeric) Number of bytes used\n"
@@ -483,19 +501,100 @@ UniValue getmemoryinfo(const JSONRPCRequest& request)
" \"chunks_free\": xxxxx, (numeric) Number unused chunks\n"
" }\n"
"}\n"
+ "\nResult (mode \"mallocinfo\"):\n"
+ "\"<malloc version=\"1\">...\"\n"
"\nExamples:\n"
+ HelpExampleCli("getmemoryinfo", "")
+ HelpExampleRpc("getmemoryinfo", "")
);
- UniValue obj(UniValue::VOBJ);
- obj.push_back(Pair("locked", RPCLockedMemoryInfo()));
- return obj;
+
+ std::string mode = request.params[0].isNull() ? "stats" : request.params[0].get_str();
+ if (mode == "stats") {
+ UniValue obj(UniValue::VOBJ);
+ obj.push_back(Pair("locked", RPCLockedMemoryInfo()));
+ return obj;
+ } else if (mode == "mallocinfo") {
+#ifdef HAVE_MALLOC_INFO
+ return RPCMallocInfo();
+#else
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "mallocinfo is only available when compiled with glibc 2.10+");
+#endif
+ } else {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "unknown mode " + mode);
+ }
+}
+
+uint32_t getCategoryMask(UniValue cats) {
+ cats = cats.get_array();
+ uint32_t mask = 0;
+ for (unsigned int i = 0; i < cats.size(); ++i) {
+ uint32_t flag = 0;
+ std::string cat = cats[i].get_str();
+ if (!GetLogCategory(&flag, &cat)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "unknown logging category " + cat);
+ }
+ mask |= flag;
+ }
+ return mask;
+}
+
+UniValue logging(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() > 2) {
+ throw std::runtime_error(
+ "logging [include,...] <exclude>\n"
+ "Gets and sets the logging configuration.\n"
+ "When called without an argument, returns the list of categories that are currently being debug logged.\n"
+ "When called with arguments, adds or removes categories from debug logging.\n"
+ "The valid logging categories are: " + ListLogCategories() + "\n"
+ "libevent logging is configured on startup and cannot be modified by this RPC during runtime."
+ "Arguments:\n"
+ "1. \"include\" (array of strings) add debug logging for these categories.\n"
+ "2. \"exclude\" (array of strings) remove debug logging for these categories.\n"
+ "\nResult: <categories> (string): a list of the logging categories that are active.\n"
+ "\nExamples:\n"
+ + HelpExampleCli("logging", "\"[\\\"all\\\"]\" \"[\\\"http\\\"]\"")
+ + HelpExampleRpc("logging", "[\"all\"], \"[libevent]\"")
+ );
+ }
+
+ uint32_t originalLogCategories = logCategories;
+ if (request.params[0].isArray()) {
+ logCategories |= getCategoryMask(request.params[0]);
+ }
+
+ if (request.params[1].isArray()) {
+ logCategories &= ~getCategoryMask(request.params[1]);
+ }
+
+ // Update libevent logging if BCLog::LIBEVENT has changed.
+ // If the library version doesn't allow it, UpdateHTTPServerLogging() returns false,
+ // in which case we should clear the BCLog::LIBEVENT flag.
+ // Throw an error if the user has explicitly asked to change only the libevent
+ // flag and it failed.
+ uint32_t changedLogCategories = originalLogCategories ^ logCategories;
+ if (changedLogCategories & BCLog::LIBEVENT) {
+ if (!UpdateHTTPServerLogging(logCategories & BCLog::LIBEVENT)) {
+ logCategories &= ~BCLog::LIBEVENT;
+ if (changedLogCategories == BCLog::LIBEVENT) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "libevent logging cannot be updated when using libevent before v2.1.1.");
+ }
+ }
+ }
+
+ UniValue result(UniValue::VOBJ);
+ std::vector<CLogCategoryActive> vLogCatActive = ListActiveLogCategories();
+ for (const auto& logCatActive : vLogCatActive) {
+ result.pushKV(logCatActive.category, logCatActive.active);
+ }
+
+ return result;
}
UniValue echo(const JSONRPCRequest& request)
{
if (request.fHelp)
- throw runtime_error(
+ throw std::runtime_error(
"echo|echojson \"message\" ...\n"
"\nSimply echo back the input arguments. This command is for testing.\n"
"\nThe difference between echo and echojson is that echojson has argument conversion enabled in the client-side table in"
@@ -506,19 +605,19 @@ UniValue echo(const JSONRPCRequest& request)
}
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafeMode
+{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
- { "control", "getinfo", &getinfo, true, {} }, /* uses wallet if enabled */
- { "control", "getmemoryinfo", &getmemoryinfo, true, {} },
- { "util", "validateaddress", &validateaddress, true, {"address"} }, /* uses wallet if enabled */
- { "util", "createmultisig", &createmultisig, true, {"nrequired","keys"} },
- { "util", "verifymessage", &verifymessage, true, {"address","signature","message"} },
- { "util", "signmessagewithprivkey", &signmessagewithprivkey, true, {"privkey","message"} },
+ { "control", "getmemoryinfo", &getmemoryinfo, {"mode"} },
+ { "util", "validateaddress", &validateaddress, {"address"} }, /* uses wallet if enabled */
+ { "util", "createmultisig", &createmultisig, {"nrequired","keys"} },
+ { "util", "verifymessage", &verifymessage, {"address","signature","message"} },
+ { "util", "signmessagewithprivkey", &signmessagewithprivkey, {"privkey","message"} },
/* Not shown in help */
- { "hidden", "setmocktime", &setmocktime, true, {"timestamp"}},
- { "hidden", "echo", &echo, true, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
- { "hidden", "echojson", &echo, true, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
+ { "hidden", "setmocktime", &setmocktime, {"timestamp"}},
+ { "hidden", "echo", &echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
+ { "hidden", "echojson", &echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
+ { "hidden", "logging", &logging, {"include", "exclude"}},
};
void RegisterMiscRPCCommands(CRPCTable &t)
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 27b9963a10..a3d3df26a3 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -6,10 +6,12 @@
#include "chainparams.h"
#include "clientversion.h"
+#include "core_io.h"
#include "validation.h"
#include "net.h"
#include "net_processing.h"
#include "netbase.h"
+#include "policy/policy.h"
#include "protocol.h"
#include "sync.h"
#include "timedata.h"
@@ -17,17 +19,14 @@
#include "util.h"
#include "utilstrencodings.h"
#include "version.h"
-
-#include <boost/foreach.hpp>
+#include "warnings.h"
#include <univalue.h>
-using namespace std;
-
UniValue getconnectioncount(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getconnectioncount\n"
"\nReturns the number of connections to other nodes.\n"
"\nResult:\n"
@@ -46,7 +45,7 @@ UniValue getconnectioncount(const JSONRPCRequest& request)
UniValue ping(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"ping\n"
"\nRequests that a ping be sent to all other nodes, to measure ping time.\n"
"Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds.\n"
@@ -69,15 +68,16 @@ UniValue ping(const JSONRPCRequest& request)
UniValue getpeerinfo(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getpeerinfo\n"
"\nReturns data about each connected network node as a json array of objects.\n"
"\nResult:\n"
"[\n"
" {\n"
" \"id\": n, (numeric) Peer index\n"
- " \"addr\":\"host:port\", (string) The ip address and port of the peer\n"
- " \"addrlocal\":\"ip:port\", (string) local address\n"
+ " \"addr\":\"host:port\", (string) The IP address and port of the peer\n"
+ " \"addrbind\":\"ip:port\", (string) Bind address of the connection to the peer\n"
+ " \"addrlocal\":\"ip:port\", (string) Local address as reported by the peer\n"
" \"services\":\"xxxxxxxxxxxxxxxx\", (string) The services offered\n"
" \"relaytxes\":true|false, (boolean) Whether peer has asked us to relay transactions to it\n"
" \"lastsend\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last send\n"
@@ -101,7 +101,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
" n, (numeric) The heights of blocks we're currently asking from this peer\n"
" ...\n"
" ],\n"
- " \"whitelisted\": true|false, (boolean) Whether the peer is whitelisted\n"
+ " \"whitelisted\": true|false, (boolean) Whether the peer is whitelisted\n"
" \"bytessent_per_msg\": {\n"
" \"addr\": n, (numeric) The total bytes sent aggregated by message type\n"
" ...\n"
@@ -121,12 +121,12 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
- vector<CNodeStats> vstats;
+ std::vector<CNodeStats> vstats;
g_connman->GetNodeStats(vstats);
UniValue ret(UniValue::VARR);
- BOOST_FOREACH(const CNodeStats& stats, vstats) {
+ for (const CNodeStats& stats : vstats) {
UniValue obj(UniValue::VOBJ);
CNodeStateStats statestats;
bool fStateStats = GetNodeStateStats(stats.nodeid, statestats);
@@ -134,6 +134,8 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
obj.push_back(Pair("addr", stats.addrName));
if (!(stats.addrLocal.empty()))
obj.push_back(Pair("addrlocal", stats.addrLocal));
+ if (stats.addrBind.IsValid())
+ obj.push_back(Pair("addrbind", stats.addrBind.ToString()));
obj.push_back(Pair("services", strprintf("%016x", stats.nServices)));
obj.push_back(Pair("relaytxes", stats.fRelayTxes));
obj.push_back(Pair("lastsend", stats.nLastSend));
@@ -144,13 +146,13 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
obj.push_back(Pair("timeoffset", stats.nTimeOffset));
if (stats.dPingTime > 0.0)
obj.push_back(Pair("pingtime", stats.dPingTime));
- if (stats.dMinPing < std::numeric_limits<int64_t>::max()/1e6)
+ if (stats.dMinPing < static_cast<double>(std::numeric_limits<int64_t>::max())/1e6)
obj.push_back(Pair("minping", stats.dMinPing));
if (stats.dPingWait > 0.0)
obj.push_back(Pair("pingwait", stats.dPingWait));
obj.push_back(Pair("version", stats.nVersion));
// Use the sanitized form of subver here, to avoid tricksy remote peers from
- // corrupting or modifiying the JSON output by putting special characters in
+ // corrupting or modifying the JSON output by putting special characters in
// their ver message.
obj.push_back(Pair("subver", stats.cleanSubVer));
obj.push_back(Pair("inbound", stats.fInbound));
@@ -161,7 +163,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
obj.push_back(Pair("synced_headers", statestats.nSyncHeight));
obj.push_back(Pair("synced_blocks", statestats.nCommonHeight));
UniValue heights(UniValue::VARR);
- BOOST_FOREACH(int height, statestats.vHeightInFlight) {
+ for (int height : statestats.vHeightInFlight) {
heights.push_back(height);
}
obj.push_back(Pair("inflight", heights));
@@ -169,14 +171,14 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
obj.push_back(Pair("whitelisted", stats.fWhitelisted));
UniValue sendPerMsgCmd(UniValue::VOBJ);
- BOOST_FOREACH(const mapMsgCmdSize::value_type &i, stats.mapSendBytesPerMsgCmd) {
+ for (const mapMsgCmdSize::value_type &i : stats.mapSendBytesPerMsgCmd) {
if (i.second > 0)
sendPerMsgCmd.push_back(Pair(i.first, i.second));
}
obj.push_back(Pair("bytessent_per_msg", sendPerMsgCmd));
UniValue recvPerMsgCmd(UniValue::VOBJ);
- BOOST_FOREACH(const mapMsgCmdSize::value_type &i, stats.mapRecvBytesPerMsgCmd) {
+ for (const mapMsgCmdSize::value_type &i : stats.mapRecvBytesPerMsgCmd) {
if (i.second > 0)
recvPerMsgCmd.push_back(Pair(i.first, i.second));
}
@@ -190,14 +192,14 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
UniValue addnode(const JSONRPCRequest& request)
{
- string strCommand;
- if (request.params.size() == 2)
+ std::string strCommand;
+ if (!request.params[1].isNull())
strCommand = request.params[1].get_str();
if (request.fHelp || request.params.size() != 2 ||
(strCommand != "onetry" && strCommand != "add" && strCommand != "remove"))
- throw runtime_error(
+ throw std::runtime_error(
"addnode \"node\" \"add|remove|onetry\"\n"
- "\nAttempts add or remove a node from the addnode list.\n"
+ "\nAttempts to add or remove a node from the addnode list.\n"
"Or try a connection to a node once.\n"
"\nArguments:\n"
"1. \"node\" (string, required) The node (see getpeerinfo for nodes)\n"
@@ -210,12 +212,12 @@ UniValue addnode(const JSONRPCRequest& request)
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
- string strNode = request.params[0].get_str();
+ std::string strNode = request.params[0].get_str();
if (strCommand == "onetry")
{
CAddress addr;
- g_connman->OpenNetworkConnection(addr, false, NULL, strNode.c_str());
+ g_connman->OpenNetworkConnection(addr, false, nullptr, strNode.c_str());
return NullUniValue;
}
@@ -235,23 +237,43 @@ UniValue addnode(const JSONRPCRequest& request)
UniValue disconnectnode(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
- "disconnectnode \"node\" \n"
- "\nImmediately disconnects from the specified node.\n"
+ if (request.fHelp || request.params.size() == 0 || request.params.size() >= 3)
+ throw std::runtime_error(
+ "disconnectnode \"[address]\" [nodeid]\n"
+ "\nImmediately disconnects from the specified peer node.\n"
+ "\nStrictly one out of 'address' and 'nodeid' can be provided to identify the node.\n"
+ "\nTo disconnect by nodeid, either set 'address' to the empty string, or call using the named 'nodeid' argument only.\n"
"\nArguments:\n"
- "1. \"node\" (string, required) The node (see getpeerinfo for nodes)\n"
+ "1. \"address\" (string, optional) The IP address/port of the node\n"
+ "2. \"nodeid\" (number, optional) The node ID (see getpeerinfo for node IDs)\n"
"\nExamples:\n"
+ HelpExampleCli("disconnectnode", "\"192.168.0.6:8333\"")
+ + HelpExampleCli("disconnectnode", "\"\" 1")
+ HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"")
+ + HelpExampleRpc("disconnectnode", "\"\", 1")
);
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
- bool ret = g_connman->DisconnectNode(request.params[0].get_str());
- if (!ret)
+ bool success;
+ const UniValue &address_arg = request.params[0];
+ const UniValue &id_arg = request.params[1];
+
+ if (!address_arg.isNull() && id_arg.isNull()) {
+ /* handle disconnect-by-address */
+ success = g_connman->DisconnectNode(address_arg.get_str());
+ } else if (!id_arg.isNull() && (address_arg.isNull() || (address_arg.isStr() && address_arg.get_str().empty()))) {
+ /* handle disconnect-by-id */
+ NodeId nodeid = (NodeId) id_arg.get_int64();
+ success = g_connman->DisconnectNode(nodeid);
+ } else {
+ throw JSONRPCError(RPC_INVALID_PARAMS, "Only one of address and nodeid should be provided.");
+ }
+
+ if (!success) {
throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes");
+ }
return NullUniValue;
}
@@ -259,7 +281,7 @@ UniValue disconnectnode(const JSONRPCRequest& request)
UniValue getaddednodeinfo(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 1)
- throw runtime_error(
+ throw std::runtime_error(
"getaddednodeinfo ( \"node\" )\n"
"\nReturns information about the given added node, or all added nodes\n"
"(note that onetry addnodes are not listed here)\n"
@@ -268,7 +290,7 @@ UniValue getaddednodeinfo(const JSONRPCRequest& request)
"\nResult:\n"
"[\n"
" {\n"
- " \"addednode\" : \"192.168.0.201\", (string) The node ip address or name (as provided to addnode)\n"
+ " \"addednode\" : \"192.168.0.201\", (string) The node IP address or name (as provided to addnode)\n"
" \"connected\" : true|false, (boolean) If connected\n"
" \"addresses\" : [ (list of objects) Only when connected = true\n"
" {\n"
@@ -280,9 +302,8 @@ UniValue getaddednodeinfo(const JSONRPCRequest& request)
" ,...\n"
"]\n"
"\nExamples:\n"
- + HelpExampleCli("getaddednodeinfo", "true")
- + HelpExampleCli("getaddednodeinfo", "true \"192.168.0.201\"")
- + HelpExampleRpc("getaddednodeinfo", "true, \"192.168.0.201\"")
+ + HelpExampleCli("getaddednodeinfo", "\"192.168.0.201\"")
+ + HelpExampleRpc("getaddednodeinfo", "\"192.168.0.201\"")
);
if(!g_connman)
@@ -290,7 +311,7 @@ UniValue getaddednodeinfo(const JSONRPCRequest& request)
std::vector<AddedNodeInfo> vInfo = g_connman->GetAddedNodeInfo();
- if (request.params.size() == 1) {
+ if (!request.params[0].isNull()) {
bool found = false;
for (const AddedNodeInfo& info : vInfo) {
if (info.strAddedNode == request.params[0].get_str()) {
@@ -327,7 +348,7 @@ UniValue getaddednodeinfo(const JSONRPCRequest& request)
UniValue getnettotals(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 0)
- throw runtime_error(
+ throw std::runtime_error(
"getnettotals\n"
"\nReturns information about network traffic, including bytes in, bytes out,\n"
"and current time.\n"
@@ -375,7 +396,7 @@ static UniValue GetNetworksInfo()
for(int n=0; n<NET_MAX; ++n)
{
enum Network network = static_cast<enum Network>(n);
- if(network == NET_UNROUTABLE)
+ if(network == NET_UNROUTABLE || network == NET_INTERNAL)
continue;
proxyType proxy;
UniValue obj(UniValue::VOBJ);
@@ -383,7 +404,7 @@ static UniValue GetNetworksInfo()
obj.push_back(Pair("name", GetNetworkName(network)));
obj.push_back(Pair("limited", IsLimited(network)));
obj.push_back(Pair("reachable", IsReachable(network)));
- obj.push_back(Pair("proxy", proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string()));
+ obj.push_back(Pair("proxy", proxy.IsValid() ? proxy.proxy.ToStringIPPort() : std::string()));
obj.push_back(Pair("proxy_randomize_credentials", proxy.randomize_credentials));
networks.push_back(obj);
}
@@ -393,7 +414,7 @@ static UniValue GetNetworksInfo()
UniValue getnetworkinfo(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getnetworkinfo\n"
"Returns an object containing various state info regarding P2P networking.\n"
"\nResult:\n"
@@ -416,7 +437,8 @@ UniValue getnetworkinfo(const JSONRPCRequest& request)
" }\n"
" ,...\n"
" ],\n"
- " \"relayfee\": x.xxxxxxxx, (numeric) minimum relay fee for non-free transactions in " + CURRENCY_UNIT + "/kB\n"
+ " \"relayfee\": x.xxxxxxxx, (numeric) minimum relay fee for transactions in " + CURRENCY_UNIT + "/kB\n"
+ " \"incrementalfee\": x.xxxxxxxx, (numeric) minimum fee increment for mempool limiting or BIP 125 replacement in " + CURRENCY_UNIT + "/kB\n"
" \"localaddresses\": [ (array) list of local addresses\n"
" {\n"
" \"address\": \"xxxx\", (string) network address\n"
@@ -425,7 +447,7 @@ UniValue getnetworkinfo(const JSONRPCRequest& request)
" }\n"
" ,...\n"
" ]\n"
- " \"warnings\": \"...\" (string) any network warnings\n"
+ " \"warnings\": \"...\" (string) any network and blockchain warnings\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getnetworkinfo", "")
@@ -447,10 +469,11 @@ UniValue getnetworkinfo(const JSONRPCRequest& request)
}
obj.push_back(Pair("networks", GetNetworksInfo()));
obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())));
+ obj.push_back(Pair("incrementalfee", ValueFromAmount(::incrementalRelayFee.GetFeePerK())));
UniValue localAddresses(UniValue::VARR);
{
LOCK(cs_mapLocalHost);
- BOOST_FOREACH(const PAIRTYPE(CNetAddr, LocalServiceInfo) &item, mapLocalHost)
+ for (const std::pair<CNetAddr, LocalServiceInfo> &item : mapLocalHost)
{
UniValue rec(UniValue::VOBJ);
rec.push_back(Pair("address", item.first.ToString()));
@@ -466,19 +489,19 @@ UniValue getnetworkinfo(const JSONRPCRequest& request)
UniValue setban(const JSONRPCRequest& request)
{
- string strCommand;
- if (request.params.size() >= 2)
+ std::string strCommand;
+ if (!request.params[1].isNull())
strCommand = request.params[1].get_str();
if (request.fHelp || request.params.size() < 2 ||
(strCommand != "add" && strCommand != "remove"))
- throw runtime_error(
+ throw std::runtime_error(
"setban \"subnet\" \"add|remove\" (bantime) (absolute)\n"
- "\nAttempts add or remove a IP/Subnet from the banned list.\n"
+ "\nAttempts to add or remove an IP/Subnet from the banned list.\n"
"\nArguments:\n"
- "1. \"subnet\" (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"
+ "1. \"subnet\" (string, required) The IP/Subnet (see getpeerinfo for nodes IP) with an optional netmask (default is /32 = single IP)\n"
+ "2. \"command\" (string, required) 'add' to add an IP/Subnet to the list, 'remove' to remove an 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 an 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\"")
@@ -491,7 +514,7 @@ UniValue setban(const JSONRPCRequest& request)
CNetAddr netAddr;
bool isSubnet = false;
- if (request.params[0].get_str().find("/") != string::npos)
+ if (request.params[0].get_str().find("/") != std::string::npos)
isSubnet = true;
if (!isSubnet) {
@@ -503,7 +526,7 @@ UniValue setban(const JSONRPCRequest& request)
LookupSubNet(request.params[0].get_str().c_str(), subNet);
if (! (isSubnet ? subNet.IsValid() : netAddr.IsValid()) )
- throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Invalid IP/Subnet");
+ throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Invalid IP/Subnet");
if (strCommand == "add")
{
@@ -511,11 +534,11 @@ UniValue setban(const JSONRPCRequest& request)
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned");
int64_t banTime = 0; //use standard bantime if not specified
- if (request.params.size() >= 3 && !request.params[2].isNull())
+ if (!request.params[2].isNull())
banTime = request.params[2].get_int64();
bool absolute = false;
- if (request.params.size() == 4 && request.params[3].isTrue())
+ if (request.params[3].isTrue())
absolute = true;
isSubnet ? g_connman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : g_connman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);
@@ -523,7 +546,7 @@ UniValue setban(const JSONRPCRequest& request)
else if(strCommand == "remove")
{
if (!( isSubnet ? g_connman->Unban(subNet) : g_connman->Unban(netAddr) ))
- throw JSONRPCError(RPC_MISC_ERROR, "Error: Unban failed");
+ throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Unban failed. Requested address/subnet was not previously banned.");
}
return NullUniValue;
}
@@ -531,7 +554,7 @@ UniValue setban(const JSONRPCRequest& request)
UniValue listbanned(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"listbanned\n"
"\nList all banned IPs/Subnets.\n"
"\nExamples:\n"
@@ -564,7 +587,7 @@ UniValue listbanned(const JSONRPCRequest& request)
UniValue clearbanned(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"clearbanned\n"
"\nClear all banned IPs.\n"
"\nExamples:\n"
@@ -582,7 +605,7 @@ UniValue clearbanned(const JSONRPCRequest& request)
UniValue setnetworkactive(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1) {
- throw runtime_error(
+ throw std::runtime_error(
"setnetworkactive true|false\n"
"\nDisable/enable all p2p network activity.\n"
"\nArguments:\n"
@@ -600,20 +623,20 @@ UniValue setnetworkactive(const JSONRPCRequest& request)
}
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafeMode
+{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
- { "network", "getconnectioncount", &getconnectioncount, true, {} },
- { "network", "ping", &ping, true, {} },
- { "network", "getpeerinfo", &getpeerinfo, true, {} },
- { "network", "addnode", &addnode, true, {"node","command"} },
- { "network", "disconnectnode", &disconnectnode, true, {"node"} },
- { "network", "getaddednodeinfo", &getaddednodeinfo, true, {"node"} },
- { "network", "getnettotals", &getnettotals, true, {} },
- { "network", "getnetworkinfo", &getnetworkinfo, true, {} },
- { "network", "setban", &setban, true, {"subnet", "command", "bantime", "absolute"} },
- { "network", "listbanned", &listbanned, true, {} },
- { "network", "clearbanned", &clearbanned, true, {} },
- { "network", "setnetworkactive", &setnetworkactive, true, {"state"} },
+ { "network", "getconnectioncount", &getconnectioncount, {} },
+ { "network", "ping", &ping, {} },
+ { "network", "getpeerinfo", &getpeerinfo, {} },
+ { "network", "addnode", &addnode, {"node","command"} },
+ { "network", "disconnectnode", &disconnectnode, {"address", "nodeid"} },
+ { "network", "getaddednodeinfo", &getaddednodeinfo, {"node"} },
+ { "network", "getnettotals", &getnettotals, {} },
+ { "network", "getnetworkinfo", &getnetworkinfo, {} },
+ { "network", "setban", &setban, {"subnet", "command", "bantime", "absolute"} },
+ { "network", "listbanned", &listbanned, {} },
+ { "network", "clearbanned", &clearbanned, {} },
+ { "network", "setnetworkactive", &setnetworkactive, {"state"} },
};
void RegisterNetRPCCommands(CRPCTable &t)
diff --git a/src/rpc/protocol.cpp b/src/rpc/protocol.cpp
index dc710d939f..1f4ae75b18 100644
--- a/src/rpc/protocol.cpp
+++ b/src/rpc/protocol.cpp
@@ -15,18 +15,16 @@
#include <stdint.h>
#include <fstream>
-using namespace std;
-
/**
* 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
*/
-UniValue JSONRPCRequestObj(const string& strMethod, const UniValue& params, const UniValue& id)
+UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id)
{
UniValue request(UniValue::VOBJ);
request.push_back(Pair("method", strMethod));
@@ -47,13 +45,13 @@ UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const Un
return reply;
}
-string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id)
+std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id)
{
UniValue reply = JSONRPCReplyObj(result, error, id);
return reply.write() + "\n";
}
-UniValue JSONRPCError(int code, const string& message)
+UniValue JSONRPCError(int code, const std::string& message)
{
UniValue error(UniValue::VOBJ);
error.push_back(Pair("code", code));
@@ -68,9 +66,14 @@ static const std::string COOKIEAUTH_USER = "__cookie__";
/** Default name for auth cookie file */
static const std::string COOKIEAUTH_FILE = ".cookie";
-boost::filesystem::path GetAuthCookieFile()
+/** Get name of RPC authentication cookie file */
+static fs::path GetAuthCookieFile(bool temp=false)
{
- boost::filesystem::path path(GetArg("-rpccookiefile", COOKIEAUTH_FILE));
+ std::string arg = gArgs.GetArg("-rpccookiefile", COOKIEAUTH_FILE);
+ if (temp) {
+ arg += ".tmp";
+ }
+ fs::path path(arg);
if (!path.is_complete()) path = GetDataDir() / path;
return path;
}
@@ -86,14 +89,20 @@ bool GenerateAuthCookie(std::string *cookie_out)
* 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());
+ fs::path filepath_tmp = GetAuthCookieFile(true);
+ file.open(filepath_tmp.string().c_str());
if (!file.is_open()) {
- LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath.string());
+ LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath_tmp.string());
return false;
}
file << cookie;
file.close();
+
+ fs::path filepath = GetAuthCookieFile(false);
+ if (!RenameOver(filepath_tmp, filepath)) {
+ LogPrintf("Unable to rename cookie authentication file %s to %s\n", filepath_tmp.string(), filepath.string());
+ return false;
+ }
LogPrintf("Generated RPC authentication cookie %s\n", filepath.string());
if (cookie_out)
@@ -105,7 +114,7 @@ bool GetAuthCookie(std::string *cookie_out)
{
std::ifstream file;
std::string cookie;
- boost::filesystem::path filepath = GetAuthCookieFile();
+ fs::path filepath = GetAuthCookieFile();
file.open(filepath.string().c_str());
if (!file.is_open())
return false;
@@ -120,9 +129,28 @@ bool GetAuthCookie(std::string *cookie_out)
void DeleteAuthCookie()
{
try {
- boost::filesystem::remove(GetAuthCookieFile());
- } catch (const boost::filesystem::filesystem_error& e) {
+ fs::remove(GetAuthCookieFile());
+ } catch (const fs::filesystem_error& e) {
LogPrintf("%s: Unable to remove random auth cookie file: %s\n", __func__, e.what());
}
}
+std::vector<UniValue> JSONRPCProcessBatchReply(const UniValue &in, size_t num)
+{
+ if (!in.isArray()) {
+ throw std::runtime_error("Batch must be an array");
+ }
+ std::vector<UniValue> batch(num);
+ for (size_t i=0; i<in.size(); ++i) {
+ const UniValue &rec = in[i];
+ if (!rec.isObject()) {
+ throw std::runtime_error("Batch member must be object");
+ }
+ size_t id = rec["id"].get_int();
+ if (id >= num) {
+ throw std::runtime_error("Batch member id larger than size");
+ }
+ batch[id] = rec;
+ }
+ return batch;
+}
diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h
index 47e56e712b..cb668f3db9 100644
--- a/src/rpc/protocol.h
+++ b/src/rpc/protocol.h
@@ -6,11 +6,12 @@
#ifndef BITCOIN_RPCPROTOCOL_H
#define BITCOIN_RPCPROTOCOL_H
+#include "fs.h"
+
#include <list>
#include <map>
#include <stdint.h>
#include <string>
-#include <boost/filesystem.hpp>
#include <univalue.h>
@@ -31,9 +32,15 @@ enum HTTPStatusCode
enum RPCErrorCode
{
//! Standard JSON-RPC 2.0 errors
+ // RPC_INVALID_REQUEST is internally mapped to HTTP_BAD_REQUEST (400).
+ // It should not be used for application-layer errors.
RPC_INVALID_REQUEST = -32600,
+ // RPC_METHOD_NOT_FOUND is internally mapped to HTTP_NOT_FOUND (404).
+ // It should not be used for application-layer errors.
RPC_METHOD_NOT_FOUND = -32601,
RPC_INVALID_PARAMS = -32602,
+ // RPC_INTERNAL_ERROR should only be used for genuine errors in bitcoind
+ // (for example datadir corruption).
RPC_INTERNAL_ERROR = -32603,
RPC_PARSE_ERROR = -32700,
@@ -50,6 +57,7 @@ enum RPCErrorCode
RPC_VERIFY_REJECTED = -26, //!< Transaction or block was rejected by network rules
RPC_VERIFY_ALREADY_IN_CHAIN = -27, //!< Transaction already in chain
RPC_IN_WARMUP = -28, //!< Client still warming up
+ RPC_METHOD_DEPRECATED = -32, //!< RPC method is deprecated
//! Aliases for backward compatibility
RPC_TRANSACTION_ERROR = RPC_VERIFY_ERROR,
@@ -75,6 +83,8 @@ enum RPCErrorCode
RPC_WALLET_WRONG_ENC_STATE = -15, //!< Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)
RPC_WALLET_ENCRYPTION_FAILED = -16, //!< Failed to encrypt the wallet
RPC_WALLET_ALREADY_UNLOCKED = -17, //!< Wallet is already unlocked
+ RPC_WALLET_NOT_FOUND = -18, //!< Invalid wallet specified
+ RPC_WALLET_NOT_SPECIFIED = -19, //!< No wallet specified (error when there are multiple wallets loaded)
};
UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id);
@@ -82,13 +92,13 @@ UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const Un
std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id);
UniValue 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();
+/** Parse JSON-RPC batch reply into a vector */
+std::vector<UniValue> JSONRPCProcessBatchReply(const UniValue &in, size_t num);
#endif // BITCOIN_RPCPROTOCOL_H
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index f328543323..d860dbc244 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -14,7 +14,9 @@
#include "merkleblock.h"
#include "net.h"
#include "policy/policy.h"
+#include "policy/rbf.h"
#include "primitives/transaction.h"
+#include "rpc/safemode.h"
#include "rpc/server.h"
#include "script/script.h"
#include "script/script_error.h"
@@ -24,88 +26,23 @@
#include "uint256.h"
#include "utilstrencodings.h"
#ifdef ENABLE_WALLET
+#include "wallet/rpcwallet.h"
#include "wallet/wallet.h"
#endif
#include <stdint.h>
-#include <boost/assign/list_of.hpp>
-
#include <univalue.h>
-using namespace std;
-
-void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex)
-{
- txnouttype type;
- vector<CTxDestination> addresses;
- int nRequired;
-
- out.push_back(Pair("asm", ScriptToAsmStr(scriptPubKey)));
- if (fIncludeHex)
- out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
-
- if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) {
- out.push_back(Pair("type", GetTxnOutputType(type)));
- return;
- }
-
- out.push_back(Pair("reqSigs", nRequired));
- out.push_back(Pair("type", GetTxnOutputType(type)));
-
- 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, UniValue& entry)
{
- entry.push_back(Pair("txid", tx.GetHash().GetHex()));
- entry.push_back(Pair("hash", tx.GetWitnessHash().GetHex()));
- entry.push_back(Pair("size", (int)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION)));
- entry.push_back(Pair("vsize", (int)::GetVirtualTransactionSize(tx)));
- entry.push_back(Pair("version", tx.nVersion));
- entry.push_back(Pair("locktime", (int64_t)tx.nLockTime));
-
- UniValue vin(UniValue::VARR);
- for (unsigned int i = 0; i < tx.vin.size(); i++) {
- const CTxIn& txin = tx.vin[i];
- 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));
- UniValue o(UniValue::VOBJ);
- o.push_back(Pair("asm", ScriptToAsmStr(txin.scriptSig, true)));
- o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
- in.push_back(Pair("scriptSig", o));
- }
- if (tx.HasWitness()) {
- UniValue txinwitness(UniValue::VARR);
- for (unsigned int j = 0; j < tx.vin[i].scriptWitness.stack.size(); j++) {
- std::vector<unsigned char> item = tx.vin[i].scriptWitness.stack[j];
- txinwitness.push_back(HexStr(item.begin(), item.end()));
- }
- in.push_back(Pair("txinwitness", txinwitness));
- }
- in.push_back(Pair("sequence", (int64_t)txin.nSequence));
- vin.push_back(in);
- }
- entry.push_back(Pair("vin", vin));
- UniValue vout(UniValue::VARR);
- for (unsigned int i = 0; i < tx.vout.size(); i++) {
- const CTxOut& txout = tx.vout[i];
- UniValue out(UniValue::VOBJ);
- out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
- out.push_back(Pair("n", (int64_t)i));
- UniValue o(UniValue::VOBJ);
- ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
- out.push_back(Pair("scriptPubKey", o));
- vout.push_back(out);
- }
- entry.push_back(Pair("vout", vout));
+ // Call into TxToUniv() in bitcoin-common to decode the transaction hex.
+ //
+ // Blockchain contextual information (confirmations and blocktime) is not
+ // available to code in bitcoin-common, so we query them here and push the
+ // data into the returned UniValue.
+ TxToUniv(tx, uint256(), entry, true, RPCSerializationFlags());
if (!hashBlock.IsNull()) {
entry.push_back(Pair("blockhash", hashBlock.GetHex()));
@@ -126,7 +63,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
UniValue getrawtransaction(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"getrawtransaction \"txid\" ( verbose )\n"
"\nNOTE: By default this function only works for mempool transactions. If the -txindex option is\n"
@@ -139,7 +76,7 @@ UniValue getrawtransaction(const JSONRPCRequest& request)
"\nArguments:\n"
"1. \"txid\" (string, required) The transaction id\n"
- "2. verbose (bool, optional, default=false) If true, return a string, other return a json object\n"
+ "2. verbose (bool, optional, default=false) If false, return a string, otherwise return a json object\n"
"\nResult (if verbose is not set or set to false):\n"
"\"data\" (string) The serialized, hex-encoded data for 'txid'\n"
@@ -201,7 +138,7 @@ UniValue getrawtransaction(const JSONRPCRequest& request)
// Accept either a bool (true) or a num (>=1) to indicate verbose output.
bool fVerbose = false;
- if (request.params.size() > 1) {
+ if (!request.params[1].isNull()) {
if (request.params[1].isNum()) {
if (request.params[1].get_int() != 0) {
fVerbose = true;
@@ -214,7 +151,7 @@ UniValue getrawtransaction(const JSONRPCRequest& request)
}
else {
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid type provided. Verbose parameter must be a boolean.");
- }
+ }
}
CTransactionRef tx;
@@ -224,13 +161,10 @@ UniValue getrawtransaction(const JSONRPCRequest& request)
: "No such mempool transaction. Use -txindex to enable blockchain transaction queries") +
". Use gettransaction for wallet transactions.");
- string strHex = EncodeHexTx(*tx, RPCSerializationFlags());
-
if (!fVerbose)
- return strHex;
+ return EncodeHexTx(*tx, RPCSerializationFlags());
UniValue result(UniValue::VOBJ);
- result.push_back(Pair("hex", strHex));
TxToJSON(*tx, hashBlock, result);
return result;
}
@@ -238,14 +172,13 @@ UniValue getrawtransaction(const JSONRPCRequest& request)
UniValue gettxoutproof(const JSONRPCRequest& request)
{
if (request.fHelp || (request.params.size() != 1 && request.params.size() != 2))
- throw runtime_error(
+ throw std::runtime_error(
"gettxoutproof [\"txid\",...] ( blockhash )\n"
"\nReturns a hex-encoded proof that \"txid\" was included in a block.\n"
"\nNOTE: By default this function only works sometimes. This is when there is an\n"
"unspent output in the utxo for this transaction. To make it always work,\n"
"you need to maintain a transaction index, using the -txindex command line option or\n"
"specify the block in which the transaction is included manually (by blockhash).\n"
- "\nReturn the raw transaction data.\n"
"\nArguments:\n"
"1. \"txids\" (string) A json array of txids to filter\n"
" [\n"
@@ -257,38 +190,43 @@ UniValue gettxoutproof(const JSONRPCRequest& request)
"\"data\" (string) A string that is a serialized, hex-encoded data for the proof.\n"
);
- set<uint256> setTxids;
+ std::set<uint256> setTxids;
uint256 oneTxid;
UniValue txids = request.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());
+ throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid txid ")+txid.get_str());
uint256 hash(uint256S(txid.get_str()));
if (setTxids.count(hash))
- throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated txid: ")+txid.get_str());
+ throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated txid: ")+txid.get_str());
setTxids.insert(hash);
oneTxid = hash;
}
LOCK(cs_main);
- CBlockIndex* pblockindex = NULL;
+ CBlockIndex* pblockindex = nullptr;
uint256 hashBlock;
- if (request.params.size() > 1)
+ if (!request.params[1].isNull())
{
hashBlock = uint256S(request.params[1].get_str());
if (!mapBlockIndex.count(hashBlock))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
pblockindex = mapBlockIndex[hashBlock];
} else {
- CCoins coins;
- if (pcoinsTip->GetCoins(oneTxid, coins) && coins.nHeight > 0 && coins.nHeight <= chainActive.Height())
- pblockindex = chainActive[coins.nHeight];
+ // Loop through txids and try to find which block they're in. Exit loop once a block is found.
+ for (const auto& tx : setTxids) {
+ const Coin& coin = AccessByTxid(*pcoinsTip, tx);
+ if (!coin.IsSpent()) {
+ pblockindex = chainActive[coin.nHeight];
+ break;
+ }
+ }
}
- if (pblockindex == NULL)
+ if (pblockindex == nullptr)
{
CTransactionRef tx;
if (!GetTransaction(oneTxid, tx, Params().GetConsensus(), hashBlock, false) || hashBlock.IsNull())
@@ -307,7 +245,7 @@ UniValue gettxoutproof(const JSONRPCRequest& request)
if (setTxids.count(tx->GetHash()))
ntxFound++;
if (ntxFound != setTxids.size())
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "(Not all) transactions not found in specified block");
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Not all transactions found in specified or retrieved block");
CDataStream ssMB(SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
CMerkleBlock mb(block, setTxids);
@@ -319,7 +257,7 @@ UniValue gettxoutproof(const JSONRPCRequest& request)
UniValue verifytxoutproof(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"verifytxoutproof \"proof\"\n"
"\nVerifies that a proof points to a transaction in a block, returning the transaction it commits to\n"
"and throwing an RPC error if the block is not in our best chain\n"
@@ -335,8 +273,8 @@ UniValue verifytxoutproof(const JSONRPCRequest& request)
UniValue res(UniValue::VARR);
- vector<uint256> vMatch;
- vector<unsigned int> vIndex;
+ std::vector<uint256> vMatch;
+ std::vector<unsigned int> vIndex;
if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot)
return res;
@@ -345,16 +283,16 @@ UniValue verifytxoutproof(const JSONRPCRequest& request)
if (!mapBlockIndex.count(merkleBlock.header.GetHash()) || !chainActive.Contains(mapBlockIndex[merkleBlock.header.GetHash()]))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
- BOOST_FOREACH(const uint256& hash, vMatch)
+ for (const uint256& hash : vMatch)
res.push_back(hash.GetHex());
return res;
}
UniValue createrawtransaction(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
- throw runtime_error(
- "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,\"data\":\"hex\",...} ( locktime )\n"
+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 4)
+ throw std::runtime_error(
+ "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,\"data\":\"hex\",...} ( locktime ) ( replaceable )\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"
@@ -362,7 +300,7 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
"it is not stored in the wallet or transmitted to the network.\n"
"\nArguments:\n"
- "1. \"inputs\" (string, required) A json array of json objects\n"
+ "1. \"inputs\" (array, required) A json array of json objects\n"
" [\n"
" {\n"
" \"txid\":\"id\", (string, required) The transaction id\n"
@@ -371,13 +309,15 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
" } \n"
" ,...\n"
" ]\n"
- "2. \"outputs\" (string, required) a json object with outputs\n"
+ "2. \"outputs\" (object, required) a json object with outputs\n"
" {\n"
" \"address\": x.xxx, (numeric or string, required) The key is the bitcoin address, the numeric value (can be string) is the " + CURRENCY_UNIT + " amount\n"
" \"data\": \"hex\" (string, required) The key is \"data\", the value is hex encoded data\n"
" ,...\n"
" }\n"
"3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n"
+ "4. replaceable (boolean, optional, default=false) Marks this transaction as BIP125 replaceable.\n"
+ " Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible.\n"
"\nResult:\n"
"\"transaction\" (string) hex string of the transaction\n"
@@ -388,7 +328,7 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"data\\\":\\\"00010203\\\"}\"")
);
- RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ)(UniValue::VNUM), true);
+ RPCTypeCheck(request.params, {UniValue::VARR, UniValue::VOBJ, UniValue::VNUM}, true);
if (request.params[0].isNull() || request.params[1].isNull())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null");
@@ -397,13 +337,15 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
CMutableTransaction rawTx;
- if (request.params.size() > 2 && !request.params[2].isNull()) {
+ if (!request.params[2].isNull()) {
int64_t nLockTime = request.params[2].get_int64();
if (nLockTime < 0 || nLockTime > std::numeric_limits<uint32_t>::max())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range");
rawTx.nLockTime = nLockTime;
}
+ bool rbfOptIn = request.params[3].isTrue();
+
for (unsigned int idx = 0; idx < inputs.size(); idx++) {
const UniValue& input = inputs[idx];
const UniValue& o = input.get_obj();
@@ -417,16 +359,24 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
if (nOutput < 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
- uint32_t nSequence = (rawTx.nLockTime ? std::numeric_limits<uint32_t>::max() - 1 : std::numeric_limits<uint32_t>::max());
+ uint32_t nSequence;
+ if (rbfOptIn) {
+ nSequence = MAX_BIP125_RBF_SEQUENCE;
+ } else if (rawTx.nLockTime) {
+ nSequence = std::numeric_limits<uint32_t>::max() - 1;
+ } else {
+ nSequence = std::numeric_limits<uint32_t>::max();
+ }
// set the sequence number if passed in the parameters object
const UniValue& sequenceObj = find_value(o, "sequence");
if (sequenceObj.isNum()) {
int64_t seqNr64 = sequenceObj.get_int64();
- if (seqNr64 < 0 || seqNr64 > std::numeric_limits<uint32_t>::max())
+ if (seqNr64 < 0 || seqNr64 > std::numeric_limits<uint32_t>::max()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, sequence number is out of range");
- else
+ } else {
nSequence = (uint32_t)seqNr64;
+ }
}
CTxIn in(COutPoint(txid, nOutput), CScript(), nSequence);
@@ -434,9 +384,9 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
rawTx.vin.push_back(in);
}
- set<CBitcoinAddress> setAddress;
- vector<string> addrList = sendTo.getKeys();
- BOOST_FOREACH(const string& name_, addrList) {
+ std::set<CTxDestination> destinations;
+ std::vector<std::string> addrList = sendTo.getKeys();
+ for (const std::string& name_ : addrList) {
if (name_ == "data") {
std::vector<unsigned char> data = ParseHexV(sendTo[name_].getValStr(),"Data");
@@ -444,15 +394,16 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
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_);
+ CTxDestination destination = DecodeDestination(name_);
+ if (!IsValidDestination(destination)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + name_);
+ }
- if (setAddress.count(address))
- throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_);
- setAddress.insert(address);
+ if (!destinations.insert(destination).second) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_);
+ }
- CScript scriptPubKey = GetScriptForDestination(address.Get());
+ CScript scriptPubKey = GetScriptForDestination(destination);
CAmount nAmount = AmountFromValue(sendTo[name_]);
CTxOut out(nAmount, scriptPubKey);
@@ -460,13 +411,17 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
}
}
+ if (!request.params[3].isNull() && rbfOptIn != SignalsOptInRBF(rawTx)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter combination: Sequence number(s) contradict replaceable option");
+ }
+
return EncodeHexTx(rawTx);
}
UniValue decoderawtransaction(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"decoderawtransaction \"hexstring\"\n"
"\nReturn a JSON object representing the serialized, hex-encoded transaction.\n"
@@ -519,7 +474,7 @@ UniValue decoderawtransaction(const JSONRPCRequest& request)
);
LOCK(cs_main);
- RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR));
+ RPCTypeCheck(request.params, {UniValue::VSTR});
CMutableTransaction mtx;
@@ -527,7 +482,7 @@ UniValue decoderawtransaction(const JSONRPCRequest& request)
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
UniValue result(UniValue::VOBJ);
- TxToJSON(CTransaction(std::move(mtx)), uint256(), result);
+ TxToUniv(CTransaction(std::move(mtx)), uint256(), result, false);
return result;
}
@@ -535,7 +490,7 @@ UniValue decoderawtransaction(const JSONRPCRequest& request)
UniValue decodescript(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"decodescript \"hexstring\"\n"
"\nDecode a hex-encoded script.\n"
"\nArguments:\n"
@@ -557,17 +512,17 @@ UniValue decodescript(const JSONRPCRequest& request)
+ HelpExampleRpc("decodescript", "\"hexstring\"")
);
- RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR));
+ RPCTypeCheck(request.params, {UniValue::VSTR});
UniValue r(UniValue::VOBJ);
CScript script;
if (request.params[0].get_str().size() > 0){
- vector<unsigned char> scriptData(ParseHexV(request.params[0], "argument"));
+ std::vector<unsigned char> scriptData(ParseHexV(request.params[0], "argument"));
script = CScript(scriptData.begin(), scriptData.end());
} else {
// Empty scripts are valid
}
- ScriptPubKeyToJSON(script, r, false);
+ ScriptPubKeyToUniv(script, r, false);
UniValue type;
type = find_value(r, "type");
@@ -575,7 +530,7 @@ UniValue decodescript(const JSONRPCRequest& request)
if (type.isStr() && type.get_str() != "scripthash") {
// P2SH cannot be wrapped in a P2SH. If this script is already a P2SH,
// don't return the address for a P2SH of the P2SH.
- r.push_back(Pair("p2sh", CBitcoinAddress(CScriptID(script)).ToString()));
+ r.push_back(Pair("p2sh", EncodeDestination(CScriptID(script))));
}
return r;
@@ -587,16 +542,112 @@ static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::
UniValue entry(UniValue::VOBJ);
entry.push_back(Pair("txid", txin.prevout.hash.ToString()));
entry.push_back(Pair("vout", (uint64_t)txin.prevout.n));
+ UniValue witness(UniValue::VARR);
+ for (unsigned int i = 0; i < txin.scriptWitness.stack.size(); i++) {
+ witness.push_back(HexStr(txin.scriptWitness.stack[i].begin(), txin.scriptWitness.stack[i].end()));
+ }
+ entry.push_back(Pair("witness", witness));
entry.push_back(Pair("scriptSig", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
entry.push_back(Pair("sequence", (uint64_t)txin.nSequence));
entry.push_back(Pair("error", strMessage));
vErrorsRet.push_back(entry);
}
+UniValue combinerawtransaction(const JSONRPCRequest& request)
+{
+
+ if (request.fHelp || request.params.size() != 1)
+ throw std::runtime_error(
+ "combinerawtransaction [\"hexstring\",...]\n"
+ "\nCombine multiple partially signed transactions into one transaction.\n"
+ "The combined transaction may be another partially signed transaction or a \n"
+ "fully signed transaction."
+
+ "\nArguments:\n"
+ "1. \"txs\" (string) A json array of hex strings of partially signed transactions\n"
+ " [\n"
+ " \"hexstring\" (string) A transaction hash\n"
+ " ,...\n"
+ " ]\n"
+
+ "\nResult:\n"
+ "\"hex\" (string) The hex-encoded raw transaction with signature(s)\n"
+
+ "\nExamples:\n"
+ + HelpExampleCli("combinerawtransaction", "[\"myhex1\", \"myhex2\", \"myhex3\"]")
+ );
+
+
+ UniValue txs = request.params[0].get_array();
+ std::vector<CMutableTransaction> txVariants(txs.size());
+
+ for (unsigned int idx = 0; idx < txs.size(); idx++) {
+ if (!DecodeHexTx(txVariants[idx], txs[idx].get_str(), true)) {
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed for tx %d", idx));
+ }
+ }
+
+ if (txVariants.empty()) {
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transactions");
+ }
+
+ // mergedTx will end up with all the signatures; it
+ // starts as a clone of the rawtx:
+ CMutableTransaction mergedTx(txVariants[0]);
+
+ // Fetch previous transactions (inputs):
+ CCoinsView viewDummy;
+ CCoinsViewCache view(&viewDummy);
+ {
+ LOCK(cs_main);
+ LOCK(mempool.cs);
+ CCoinsViewCache &viewChain = *pcoinsTip;
+ CCoinsViewMemPool viewMempool(&viewChain, mempool);
+ view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
+
+ for (const CTxIn& txin : mergedTx.vin) {
+ view.AccessCoin(txin.prevout); // Load entries from viewChain into view; can fail.
+ }
+
+ view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
+ }
+
+ // Use CTransaction for the constant parts of the
+ // transaction to avoid rehashing.
+ const CTransaction txConst(mergedTx);
+ // Sign what we can:
+ for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
+ CTxIn& txin = mergedTx.vin[i];
+ const Coin& coin = view.AccessCoin(txin.prevout);
+ if (coin.IsSpent()) {
+ throw JSONRPCError(RPC_VERIFY_ERROR, "Input not found or already spent");
+ }
+ const CScript& prevPubKey = coin.out.scriptPubKey;
+ const CAmount& amount = coin.out.nValue;
+
+ SignatureData sigdata;
+
+ // ... and merge in other signatures:
+ for (const CMutableTransaction& txv : txVariants) {
+ if (txv.vin.size() > i) {
+ sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i));
+ }
+ }
+
+ UpdateTransaction(mergedTx, i, sigdata);
+ }
+
+ return EncodeHexTx(mergedTx);
+}
+
UniValue signrawtransaction(const JSONRPCRequest& request)
{
+#ifdef ENABLE_WALLET
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+#endif
+
if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
- throw runtime_error(
+ throw std::runtime_error(
"signrawtransaction \"hexstring\" ( [{\"txid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\",\"redeemScript\":\"hex\"},...] [\"privatekey1\",...] sighashtype )\n"
"\nSign inputs for raw transaction (serialized, hex-encoded).\n"
"The second optional argument (may be null) is an array of previous transaction outputs that\n"
@@ -604,7 +655,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
"The third optional argument (may be null) is an array of base58-encoded private\n"
"keys that, if given, will be the only keys used to sign the transaction.\n"
#ifdef ENABLE_WALLET
- + HelpRequiringPassphrase() + "\n"
+ + HelpRequiringPassphrase(pwallet) + "\n"
#endif
"\nArguments:\n"
@@ -654,33 +705,17 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
+ HelpExampleRpc("signrawtransaction", "\"myhex\"")
);
+ ObserveSafeMode();
#ifdef ENABLE_WALLET
- LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
+ LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : nullptr);
#else
LOCK(cs_main);
#endif
- RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR)(UniValue::VARR)(UniValue::VARR)(UniValue::VSTR), true);
-
- vector<unsigned char> txData(ParseHexV(request.params[0], "argument 1"));
- CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
- vector<CMutableTransaction> txVariants;
- while (!ssData.empty()) {
- try {
- CMutableTransaction tx;
- ssData >> tx;
- txVariants.push_back(tx);
- }
- catch (const std::exception&) {
- throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
- }
- }
-
- if (txVariants.empty())
- throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction");
+ RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VARR, UniValue::VSTR}, true);
- // mergedTx will end up with all the signatures; it
- // starts as a clone of the rawtx:
- CMutableTransaction mergedTx(txVariants[0]);
+ CMutableTransaction mtx;
+ if (!DecodeHexTx(mtx, request.params[0].get_str(), true))
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
// Fetch previous transactions (inputs):
CCoinsView viewDummy;
@@ -691,10 +726,8 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
CCoinsViewMemPool viewMempool(&viewChain, mempool);
view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
- BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) {
- const uint256& prevHash = txin.prevout.hash;
- CCoins coins;
- view.AccessCoins(prevHash); // this is certainly allowed to fail
+ for (const CTxIn& txin : mtx.vin) {
+ view.AccessCoin(txin.prevout); // Load entries from viewChain into view; can fail.
}
view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
@@ -702,7 +735,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
bool fGivenKeys = false;
CBasicKeyStore tempKeystore;
- if (request.params.size() > 2 && !request.params[2].isNull()) {
+ if (!request.params[2].isNull()) {
fGivenKeys = true;
UniValue keys = request.params[2].get_array();
for (unsigned int idx = 0; idx < keys.size(); idx++) {
@@ -718,12 +751,13 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
}
}
#ifdef ENABLE_WALLET
- else if (pwalletMain)
- EnsureWalletIsUnlocked();
+ else if (pwallet) {
+ EnsureWalletIsUnlocked(pwallet);
+ }
#endif
// Add previous txouts given in the RPC call:
- if (request.params.size() > 1 && !request.params[1].isNull()) {
+ if (!request.params[1].isNull()) {
UniValue prevTxs = request.params[1].get_array();
for (unsigned int idx = 0; idx < prevTxs.size(); idx++) {
const UniValue& p = prevTxs[idx];
@@ -745,24 +779,26 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
if (nOut < 0)
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
- vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey"));
+ COutPoint out(txid, nOut);
+ std::vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey"));
CScript scriptPubKey(pkData.begin(), pkData.end());
{
- CCoinsModifier coins = view.ModifyCoins(txid);
- if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) {
- string err("Previous output scriptPubKey mismatch:\n");
- err = err + ScriptToAsmStr(coins->vout[nOut].scriptPubKey) + "\nvs:\n"+
+ const Coin& coin = view.AccessCoin(out);
+ if (!coin.IsSpent() && coin.out.scriptPubKey != scriptPubKey) {
+ std::string err("Previous output scriptPubKey mismatch:\n");
+ err = err + ScriptToAsmStr(coin.out.scriptPubKey) + "\nvs:\n"+
ScriptToAsmStr(scriptPubKey);
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
}
- if ((unsigned int)nOut >= coins->vout.size())
- coins->vout.resize(nOut+1);
- coins->vout[nOut].scriptPubKey = scriptPubKey;
- coins->vout[nOut].nValue = 0;
+ Coin newcoin;
+ newcoin.out.scriptPubKey = scriptPubKey;
+ newcoin.out.nValue = 0;
if (prevOut.exists("amount")) {
- coins->vout[nOut].nValue = AmountFromValue(find_value(prevOut, "amount"));
+ newcoin.out.nValue = AmountFromValue(find_value(prevOut, "amount"));
}
+ newcoin.nHeight = 1;
+ view.AddCoin(out, std::move(newcoin), true);
}
// if redeemScript given and not using the local wallet (private keys
@@ -777,7 +813,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
});
UniValue v = find_value(prevOut, "redeemScript");
if (!v.isNull()) {
- vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
+ std::vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
CScript redeemScript(rsData.begin(), rsData.end());
tempKeystore.AddCScript(redeemScript);
}
@@ -786,23 +822,22 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
}
#ifdef ENABLE_WALLET
- const CKeyStore& keystore = ((fGivenKeys || !pwalletMain) ? tempKeystore : *pwalletMain);
+ const CKeyStore& keystore = ((fGivenKeys || !pwallet) ? tempKeystore : *pwallet);
#else
const CKeyStore& keystore = tempKeystore;
#endif
int nHashType = SIGHASH_ALL;
- if (request.params.size() > 3 && !request.params[3].isNull()) {
- static map<string, int> mapSigHashValues =
- boost::assign::map_list_of
- (string("ALL"), int(SIGHASH_ALL))
- (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
- (string("NONE"), int(SIGHASH_NONE))
- (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
- (string("SINGLE"), int(SIGHASH_SINGLE))
- (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
- ;
- string strHashType = request.params[3].get_str();
+ if (!request.params[3].isNull()) {
+ static std::map<std::string, int> mapSigHashValues = {
+ {std::string("ALL"), int(SIGHASH_ALL)},
+ {std::string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)},
+ {std::string("NONE"), int(SIGHASH_NONE)},
+ {std::string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY)},
+ {std::string("SINGLE"), int(SIGHASH_SINGLE)},
+ {std::string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY)},
+ };
+ std::string strHashType = request.params[3].get_str();
if (mapSigHashValues.count(strHashType))
nHashType = mapSigHashValues[strHashType];
else
@@ -816,39 +851,40 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
// Use CTransaction for the constant parts of the
// transaction to avoid rehashing.
- const CTransaction txConst(mergedTx);
+ const CTransaction txConst(mtx);
// Sign what we can:
- for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
- CTxIn& txin = mergedTx.vin[i];
- const CCoins* coins = view.AccessCoins(txin.prevout.hash);
- if (coins == NULL || !coins->IsAvailable(txin.prevout.n)) {
+ for (unsigned int i = 0; i < mtx.vin.size(); i++) {
+ CTxIn& txin = mtx.vin[i];
+ const Coin& coin = view.AccessCoin(txin.prevout);
+ if (coin.IsSpent()) {
TxInErrorToJSON(txin, vErrors, "Input not found or already spent");
continue;
}
- const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey;
- const CAmount& amount = coins->vout[txin.prevout.n].nValue;
+ const CScript& prevPubKey = coin.out.scriptPubKey;
+ const CAmount& amount = coin.out.nValue;
SignatureData sigdata;
// Only sign SIGHASH_SINGLE if there's a corresponding output:
- if (!fHashSingle || (i < mergedTx.vout.size()))
- ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata);
+ if (!fHashSingle || (i < mtx.vout.size()))
+ ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mtx, i, amount, nHashType), prevPubKey, sigdata);
+ sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(mtx, i));
- // ... and merge in other signatures:
- BOOST_FOREACH(const CMutableTransaction& txv, txVariants) {
- sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i));
- }
-
- UpdateTransaction(mergedTx, i, sigdata);
+ UpdateTransaction(mtx, i, sigdata);
ScriptError serror = SCRIPT_ERR_OK;
if (!VerifyScript(txin.scriptSig, prevPubKey, &txin.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) {
- TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
+ if (serror == SCRIPT_ERR_INVALID_STACK_OPERATION) {
+ // Unable to sign input and verification failed (possible attempt to partially sign).
+ TxInErrorToJSON(txin, vErrors, "Unable to sign input, invalid stack size (possibly missing key)");
+ } else {
+ TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
+ }
}
}
bool fComplete = vErrors.empty();
UniValue result(UniValue::VOBJ);
- result.push_back(Pair("hex", EncodeHexTx(mergedTx)));
+ result.push_back(Pair("hex", EncodeHexTx(mtx)));
result.push_back(Pair("complete", fComplete));
if (!vErrors.empty()) {
result.push_back(Pair("errors", vErrors));
@@ -860,7 +896,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
UniValue sendrawtransaction(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"sendrawtransaction \"hexstring\" ( allowhighfees )\n"
"\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\n"
"\nAlso see createrawtransaction and signrawtransaction calls.\n"
@@ -880,8 +916,9 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
+ HelpExampleRpc("sendrawtransaction", "\"signedhex\"")
);
+ ObserveSafeMode();
LOCK(cs_main);
- RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL));
+ RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL});
// parse hex string from parameter
CMutableTransaction mtx;
@@ -890,20 +927,23 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
const uint256& hashTx = tx->GetHash();
- bool fLimitFree = false;
CAmount nMaxRawTxFee = maxTxFee;
- if (request.params.size() > 1 && request.params[1].get_bool())
+ if (!request.params[1].isNull() && request.params[1].get_bool())
nMaxRawTxFee = 0;
CCoinsViewCache &view = *pcoinsTip;
- const CCoins* existingCoins = view.AccessCoins(hashTx);
+ bool fHaveChain = false;
+ for (size_t o = 0; !fHaveChain && o < tx->vout.size(); o++) {
+ const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o));
+ fHaveChain = !existingCoin.IsSpent();
+ }
bool fHaveMempool = mempool.exists(hashTx);
- bool fHaveChain = existingCoins && existingCoins->nHeight < 1000000000;
if (!fHaveMempool && !fHaveChain) {
// push to local node and sync with wallets
CValidationState state;
bool fMissingInputs;
- if (!AcceptToMemoryPool(mempool, state, std::move(tx), fLimitFree, &fMissingInputs, false, nMaxRawTxFee)) {
+ if (!AcceptToMemoryPool(mempool, state, std::move(tx), &fMissingInputs,
+ nullptr /* plTxnReplaced */, false /* bypass_limits */, nMaxRawTxFee)) {
if (state.IsInvalid()) {
throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
} else {
@@ -928,17 +968,18 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
}
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafeMode
+{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
- { "rawtransactions", "getrawtransaction", &getrawtransaction, true, {"txid","verbose"} },
- { "rawtransactions", "createrawtransaction", &createrawtransaction, true, {"transactions","outputs","locktime"} },
- { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true, {"hexstring"} },
- { "rawtransactions", "decodescript", &decodescript, true, {"hexstring"} },
- { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false, {"hexstring","allowhighfees"} },
- { "rawtransactions", "signrawtransaction", &signrawtransaction, false, {"hexstring","prevtxs","privkeys","sighashtype"} }, /* uses wallet if enabled */
-
- { "blockchain", "gettxoutproof", &gettxoutproof, true, {"txids", "blockhash"} },
- { "blockchain", "verifytxoutproof", &verifytxoutproof, true, {"proof"} },
+ { "rawtransactions", "getrawtransaction", &getrawtransaction, {"txid","verbose"} },
+ { "rawtransactions", "createrawtransaction", &createrawtransaction, {"inputs","outputs","locktime","replaceable"} },
+ { "rawtransactions", "decoderawtransaction", &decoderawtransaction, {"hexstring"} },
+ { "rawtransactions", "decodescript", &decodescript, {"hexstring"} },
+ { "rawtransactions", "sendrawtransaction", &sendrawtransaction, {"hexstring","allowhighfees"} },
+ { "rawtransactions", "combinerawtransaction", &combinerawtransaction, {"txs"} },
+ { "rawtransactions", "signrawtransaction", &signrawtransaction, {"hexstring","prevtxs","privkeys","sighashtype"} }, /* uses wallet if enabled */
+
+ { "blockchain", "gettxoutproof", &gettxoutproof, {"txids", "blockhash"} },
+ { "blockchain", "verifytxoutproof", &verifytxoutproof, {"proof"} },
};
void RegisterRawTransactionRPCCommands(CRPCTable &t)
diff --git a/src/rpc/safemode.cpp b/src/rpc/safemode.cpp
new file mode 100644
index 0000000000..24770ad47f
--- /dev/null
+++ b/src/rpc/safemode.cpp
@@ -0,0 +1,14 @@
+#include "safemode.h"
+
+#include "rpc/protocol.h"
+#include "util.h"
+#include "warnings.h"
+
+void ObserveSafeMode()
+{
+ std::string warning = GetWarnings("rpc");
+ if (warning != "" && !gArgs.GetBoolArg("-disablesafemode", DEFAULT_DISABLE_SAFEMODE)) {
+ throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, std::string("Safe mode: ") + warning);
+ }
+}
+
diff --git a/src/rpc/safemode.h b/src/rpc/safemode.h
new file mode 100644
index 0000000000..8466d6b2f9
--- /dev/null
+++ b/src/rpc/safemode.h
@@ -0,0 +1,12 @@
+// Copyright (c) 2017 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_RPC_SAFEMODE_H
+#define BITCOIN_RPC_SAFEMODE_H
+
+static const bool DEFAULT_DISABLE_SAFEMODE = true;
+
+void ObserveSafeMode();
+
+#endif // BITCOIN_RPC_SAFEMODE_H
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 1b94e10071..a73b697e01 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -6,6 +6,7 @@
#include "rpc/server.h"
#include "base58.h"
+#include "fs.h"
#include "init.h"
#include "random.h"
#include "sync.h"
@@ -16,27 +17,20 @@
#include <univalue.h>
#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 <boost/signals2/signal.hpp>
-#include <boost/thread.hpp>
#include <boost/algorithm/string/case_conv.hpp> // for to_upper()
+#include <boost/algorithm/string/classification.hpp>
+#include <boost/algorithm/string/split.hpp>
#include <memory> // for unique_ptr
#include <unordered_map>
-using namespace RPCServer;
-using namespace std;
-
static bool fRPCRunning = false;
static bool fRPCInWarmup = true;
static std::string rpcWarmupStatus("RPC server started");
static CCriticalSection cs_rpcWarmup;
/* Timer-creating functions */
-static RPCTimerInterface* timerInterface = NULL;
+static RPCTimerInterface* timerInterface = nullptr;
/* Map of name to timer. */
static std::map<std::string, std::unique_ptr<RPCTimerBase> > deadlineTimers;
@@ -45,52 +39,45 @@ static struct CRPCSignals
boost::signals2::signal<void ()> Started;
boost::signals2::signal<void ()> Stopped;
boost::signals2::signal<void (const CRPCCommand&)> PreCommand;
- boost::signals2::signal<void (const CRPCCommand&)> PostCommand;
} g_rpcSignals;
-void RPCServer::OnStarted(boost::function<void ()> slot)
+void RPCServer::OnStarted(std::function<void ()> slot)
{
g_rpcSignals.Started.connect(slot);
}
-void RPCServer::OnStopped(boost::function<void ()> slot)
+void RPCServer::OnStopped(std::function<void ()> slot)
{
g_rpcSignals.Stopped.connect(slot);
}
-void RPCServer::OnPreCommand(boost::function<void (const CRPCCommand&)> slot)
-{
- g_rpcSignals.PreCommand.connect(boost::bind(slot, _1));
-}
-
-void RPCServer::OnPostCommand(boost::function<void (const CRPCCommand&)> slot)
-{
- g_rpcSignals.PostCommand.connect(boost::bind(slot, _1));
-}
-
void RPCTypeCheck(const UniValue& params,
- const list<UniValue::VType>& typesExpected,
+ const std::list<UniValue::VType>& typesExpected,
bool fAllowNull)
{
unsigned int i = 0;
- BOOST_FOREACH(UniValue::VType t, typesExpected)
+ for (UniValue::VType t : typesExpected)
{
if (params.size() <= i)
break;
const UniValue& v = params[i];
- if (!((v.type() == t) || (fAllowNull && (v.isNull()))))
- {
- string err = strprintf("Expected type %s, got %s",
- uvTypeName(t), uvTypeName(v.type()));
- throw JSONRPCError(RPC_TYPE_ERROR, err);
+ if (!(fAllowNull && v.isNull())) {
+ RPCTypeCheckArgument(v, t);
}
i++;
}
}
+void RPCTypeCheckArgument(const UniValue& value, UniValue::VType typeExpected)
+{
+ if (value.type() != typeExpected) {
+ throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Expected type %s, got %s", uvTypeName(typeExpected), uvTypeName(value.type())));
+ }
+}
+
void RPCTypeCheckObj(const UniValue& o,
- const map<string, UniValueType>& typesExpected,
+ const std::map<std::string, UniValueType>& typesExpected,
bool fAllowNull,
bool fStrict)
{
@@ -100,7 +87,7 @@ void RPCTypeCheckObj(const UniValue& o,
throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first));
if (!(t.second.typeAny || v.type() == t.second.type || (fAllowNull && v.isNull()))) {
- string err = strprintf("Expected type %s for %s, got %s",
+ std::string err = strprintf("Expected type %s for %s, got %s",
uvTypeName(t.second.type), t.first, uvTypeName(v.type()));
throw JSONRPCError(RPC_TYPE_ERROR, err);
}
@@ -108,11 +95,11 @@ void RPCTypeCheckObj(const UniValue& o,
if (fStrict)
{
- BOOST_FOREACH(const string& k, o.getKeys())
+ for (const std::string& k : o.getKeys())
{
if (typesExpected.count(k) == 0)
{
- string err = strprintf("Unexpected key %s", k);
+ std::string err = strprintf("Unexpected key %s", k);
throw JSONRPCError(RPC_TYPE_ERROR, err);
}
}
@@ -131,19 +118,9 @@ CAmount AmountFromValue(const UniValue& value)
return amount;
}
-UniValue ValueFromAmount(const CAmount& amount)
-{
- 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 UniValue& v, string strName)
+uint256 ParseHashV(const UniValue& v, std::string strName)
{
- string strHex;
+ std::string strHex;
if (v.isStr())
strHex = v.get_str();
if (!IsHex(strHex)) // Note: IsHex("") is false
@@ -154,20 +131,20 @@ uint256 ParseHashV(const UniValue& v, string strName)
result.SetHex(strHex);
return result;
}
-uint256 ParseHashO(const UniValue& o, string strKey)
+uint256 ParseHashO(const UniValue& o, std::string strKey)
{
return ParseHashV(find_value(o, strKey), strKey);
}
-vector<unsigned char> ParseHexV(const UniValue& v, string strName)
+std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName)
{
- string strHex;
+ std::string strHex;
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 UniValue& o, string strKey)
+std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey)
{
return ParseHexV(find_value(o, strKey), strKey);
}
@@ -176,30 +153,30 @@ vector<unsigned char> ParseHexO(const UniValue& o, string strKey)
* Note: This interface may still be subject to change.
*/
-std::string CRPCTable::help(const std::string& strCommand) const
+std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest& helpreq) const
{
- string strRet;
- string category;
- set<rpcfn_type> setDone;
- vector<pair<string, const CRPCCommand*> > vCommands;
+ std::string strRet;
+ std::string category;
+ std::set<rpcfn_type> setDone;
+ std::vector<std::pair<std::string, const CRPCCommand*> > vCommands;
- for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
+ for (std::map<std::string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
vCommands.push_back(make_pair(mi->second->category + mi->first, mi->second));
sort(vCommands.begin(), vCommands.end());
- BOOST_FOREACH(const PAIRTYPE(string, const CRPCCommand*)& command, vCommands)
+ JSONRPCRequest jreq(helpreq);
+ jreq.fHelp = true;
+ jreq.params = UniValue();
+
+ for (const std::pair<std::string, const CRPCCommand*>& command : vCommands)
{
const CRPCCommand *pcmd = command.second;
- string strMethod = pcmd->name;
- // We already filter duplicates, but these deprecated screw up the sort order
- if (strMethod.find("label") != string::npos)
- continue;
+ std::string strMethod = pcmd->name;
if ((strCommand != "" || pcmd->category == "hidden") && strMethod != strCommand)
continue;
+ jreq.strMethod = strMethod;
try
{
- JSONRPCRequest jreq;
- jreq.fHelp = true;
rpcfn_type pfn = pcmd->actor;
if (setDone.insert(pfn).second)
(*pfn)(jreq);
@@ -207,10 +184,10 @@ std::string CRPCTable::help(const std::string& strCommand) const
catch (const std::exception& e)
{
// Help text is returned in an exception
- string strHelp = string(e.what());
+ std::string strHelp = std::string(e.what());
if (strCommand == "")
{
- if (strHelp.find('\n') != string::npos)
+ if (strHelp.find('\n') != std::string::npos)
strHelp = strHelp.substr(0, strHelp.find('\n'));
if (category != pcmd->category)
@@ -218,7 +195,7 @@ std::string CRPCTable::help(const std::string& strCommand) const
if (!category.empty())
strRet += "\n";
category = pcmd->category;
- string firstLetter = category.substr(0,1);
+ std::string firstLetter = category.substr(0,1);
boost::to_upper(firstLetter);
strRet += "== " + firstLetter + category.substr(1) + " ==\n";
}
@@ -235,7 +212,7 @@ std::string CRPCTable::help(const std::string& strCommand) const
UniValue help(const JSONRPCRequest& jsonRequest)
{
if (jsonRequest.fHelp || jsonRequest.params.size() > 1)
- throw runtime_error(
+ throw std::runtime_error(
"help ( \"command\" )\n"
"\nList all commands, or get help for a specified command.\n"
"\nArguments:\n"
@@ -244,11 +221,11 @@ UniValue help(const JSONRPCRequest& jsonRequest)
"\"text\" (string) The help text\n"
);
- string strCommand;
+ std::string strCommand;
if (jsonRequest.params.size() > 0)
strCommand = jsonRequest.params[0].get_str();
- return tableRPC.help(strCommand);
+ return tableRPC.help(strCommand, jsonRequest);
}
@@ -256,7 +233,7 @@ UniValue stop(const JSONRPCRequest& jsonRequest)
{
// Accept the deprecated and ignored 'detach' boolean argument
if (jsonRequest.fHelp || jsonRequest.params.size() > 1)
- throw runtime_error(
+ throw std::runtime_error(
"stop\n"
"\nStop Bitcoin server.");
// Event loop will exit after current HTTP requests have been handled, so
@@ -265,15 +242,32 @@ UniValue stop(const JSONRPCRequest& jsonRequest)
return "Bitcoin server stopping";
}
+UniValue uptime(const JSONRPCRequest& jsonRequest)
+{
+ if (jsonRequest.fHelp || jsonRequest.params.size() > 1)
+ throw std::runtime_error(
+ "uptime\n"
+ "\nReturns the total uptime of the server.\n"
+ "\nResult:\n"
+ "ttt (numeric) The number of seconds that the server has been running\n"
+ "\nExamples:\n"
+ + HelpExampleCli("uptime", "")
+ + HelpExampleRpc("uptime", "")
+ );
+
+ return GetTime() - GetStartupTime();
+}
+
/**
* Call Table
*/
static const CRPCCommand vRPCCommands[] =
-{ // category name actor (function) okSafe argNames
- // --------------------- ------------------------ ----------------------- ------ ----------
+{ // category name actor (function) argNames
+ // --------------------- ------------------------ ----------------------- ----------
/* Overall control/query calls */
- { "control", "help", &help, true, {"command"} },
- { "control", "stop", &stop, true, {} },
+ { "control", "help", &help, {"command"} },
+ { "control", "stop", &stop, {} },
+ { "control", "uptime", &uptime, {} },
};
CRPCTable::CRPCTable()
@@ -290,9 +284,9 @@ CRPCTable::CRPCTable()
const CRPCCommand *CRPCTable::operator[](const std::string &name) const
{
- map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
+ std::map<std::string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
if (it == mapCommands.end())
- return NULL;
+ return nullptr;
return (*it).second;
}
@@ -302,7 +296,7 @@ bool CRPCTable::appendCommand(const std::string& name, const CRPCCommand* pcmd)
return false;
// don't allow overwriting for now
- map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
+ std::map<std::string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
if (it != mapCommands.end())
return false;
@@ -312,7 +306,7 @@ bool CRPCTable::appendCommand(const std::string& name, const CRPCCommand* pcmd)
bool StartRPC()
{
- LogPrint("rpc", "Starting RPC\n");
+ LogPrint(BCLog::RPC, "Starting RPC\n");
fRPCRunning = true;
g_rpcSignals.Started();
return true;
@@ -320,15 +314,16 @@ bool StartRPC()
void InterruptRPC()
{
- LogPrint("rpc", "Interrupting RPC\n");
+ LogPrint(BCLog::RPC, "Interrupting RPC\n");
// Interrupt e.g. running longpolls
fRPCRunning = false;
}
void StopRPC()
{
- LogPrint("rpc", "Stopping RPC\n");
+ LogPrint(BCLog::RPC, "Stopping RPC\n");
deadlineTimers.clear();
+ DeleteAuthCookie();
g_rpcSignals.Stopped();
}
@@ -375,8 +370,7 @@ void JSONRPCRequest::parse(const UniValue& valRequest)
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));
+ LogPrint(BCLog::RPC, "ThreadRPCServer method=%s\n", SanitizeString(strMethod));
// Parse params
UniValue valParams = find_value(request, "params");
@@ -388,6 +382,13 @@ void JSONRPCRequest::parse(const UniValue& valRequest)
throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array or object");
}
+bool IsDeprecatedRPCEnabled(const std::string& method)
+{
+ const std::vector<std::string> enabled_methods = gArgs.GetArgs("-deprecatedrpc");
+
+ return find(enabled_methods.begin(), enabled_methods.end(), method) != enabled_methods.end();
+}
+
static UniValue JSONRPCExecOne(const UniValue& req)
{
UniValue rpc_result(UniValue::VOBJ);
@@ -439,8 +440,16 @@ static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, c
}
// Process expected parameters.
int hole = 0;
- for (const std::string &argName: argNames) {
- auto fr = argsIn.find(argName);
+ for (const std::string &argNamePattern: argNames) {
+ std::vector<std::string> vargNames;
+ boost::algorithm::split(vargNames, argNamePattern, boost::algorithm::is_any_of("|"));
+ auto fr = argsIn.end();
+ for (const std::string & argName : vargNames) {
+ fr = argsIn.find(argName);
+ if (fr != argsIn.end()) {
+ break;
+ }
+ }
if (fr != argsIn.end()) {
for (int i = 0; i < hole; ++i) {
// Fill hole between specified parameters with JSON nulls,
@@ -492,8 +501,6 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const
{
throw JSONRPCError(RPC_MISC_ERROR, e.what());
}
-
- g_rpcSignals.PostCommand(*pcmd);
}
std::vector<std::string> CRPCTable::listCommands() const
@@ -532,22 +539,22 @@ void RPCSetTimerInterface(RPCTimerInterface *iface)
void RPCUnsetTimerInterface(RPCTimerInterface *iface)
{
if (timerInterface == iface)
- timerInterface = NULL;
+ timerInterface = nullptr;
}
-void RPCRunLater(const std::string& name, boost::function<void(void)> func, int64_t nSeconds)
+void RPCRunLater(const std::string& name, std::function<void(void)> func, int64_t nSeconds)
{
if (!timerInterface)
throw JSONRPCError(RPC_INTERNAL_ERROR, "No timer handler registered for RPC");
deadlineTimers.erase(name);
- LogPrint("rpc", "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name());
+ LogPrint(BCLog::RPC, "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name());
deadlineTimers.emplace(name, std::unique_ptr<RPCTimerBase>(timerInterface->NewTimer(func, nSeconds*1000)));
}
int RPCSerializationFlags()
{
int flag = 0;
- if (GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) == 0)
+ if (gArgs.GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) == 0)
flag |= SERIALIZE_TRANSACTION_NO_WITNESS;
return flag;
}
diff --git a/src/rpc/server.h b/src/rpc/server.h
index fed3d8c90f..31d6304271 100644
--- a/src/rpc/server.h
+++ b/src/rpc/server.h
@@ -15,8 +15,6 @@
#include <stdint.h>
#include <string>
-#include <boost/function.hpp>
-
#include <univalue.h>
static const unsigned int DEFAULT_RPC_SERIALIZE_VERSION = 1;
@@ -25,19 +23,14 @@ class CRPCCommand;
namespace RPCServer
{
- void OnStarted(boost::function<void ()> slot);
- void OnStopped(boost::function<void ()> slot);
- void OnPreCommand(boost::function<void (const CRPCCommand&)> slot);
- void OnPostCommand(boost::function<void (const CRPCCommand&)> slot);
+ void OnStarted(std::function<void ()> slot);
+ void OnStopped(std::function<void ()> slot);
}
-class CBlockIndex;
-class CNetAddr;
-
/** Wrapper for UniValue::VType, which includes typeAny:
* Used to denote don't care type. Only used by RPCTypeCheckObj */
struct UniValueType {
- UniValueType(UniValue::VType _type) : typeAny(false), type(_type) {}
+ explicit UniValueType(UniValue::VType _type) : typeAny(false), type(_type) {}
UniValueType() : typeAny(true) {}
bool typeAny;
UniValue::VType type;
@@ -53,7 +46,7 @@ public:
std::string URI;
std::string authUser;
- JSONRPCRequest() { id = NullUniValue; params = NullUniValue; fHelp = false; }
+ JSONRPCRequest() : id(NullUniValue), params(NullUniValue), fHelp(false) {}
void parse(const UniValue& valRequest);
};
@@ -69,7 +62,7 @@ void SetRPCWarmupStatus(const std::string& newStatus);
void SetRPCWarmupFinished();
/* returns the current warmup state. */
-bool RPCIsInWarmup(std::string *statusOut);
+bool RPCIsInWarmup(std::string *outStatus);
/**
* Type-check arguments; throws JSONRPCError if wrong type given. Does not check that
@@ -78,6 +71,11 @@ bool RPCIsInWarmup(std::string *statusOut);
void RPCTypeCheck(const UniValue& params,
const std::list<UniValue::VType>& typesExpected, bool fAllowNull=false);
+/**
+ * Type-check one argument; throws JSONRPCError if wrong type given.
+ */
+void RPCTypeCheckArgument(const UniValue& value, UniValue::VType typeExpected);
+
/*
Check for expected keys/value types in an Object.
*/
@@ -111,7 +109,7 @@ public:
* 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;
+ virtual RPCTimerBase* NewTimer(std::function<void(void)>& func, int64_t millis) = 0;
};
/** Set the factory function for timers */
@@ -125,7 +123,7 @@ void RPCUnsetTimerInterface(RPCTimerInterface *iface);
* 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);
+void RPCRunLater(const std::string& name, std::function<void(void)> func, int64_t nSeconds);
typedef UniValue(*rpcfn_type)(const JSONRPCRequest& jsonRequest);
@@ -135,7 +133,6 @@ public:
std::string category;
std::string name;
rpcfn_type actor;
- bool okSafeMode;
std::vector<std::string> argNames;
};
@@ -149,7 +146,7 @@ private:
public:
CRPCTable();
const CRPCCommand* operator[](const std::string& name) const;
- std::string help(const std::string& name) const;
+ std::string help(const std::string& name, const JSONRPCRequest& helpreq) const;
/**
* Execute a method.
@@ -174,6 +171,8 @@ public:
bool appendCommand(const std::string& name, const CRPCCommand* pcmd);
};
+bool IsDeprecatedRPCEnabled(const std::string& method);
+
extern CRPCTable tableRPC;
/**
@@ -185,21 +184,14 @@ 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 UniValue& value);
-extern UniValue ValueFromAmount(const CAmount& amount);
-extern double GetDifficulty(const CBlockIndex* blockindex = NULL);
-extern std::string HelpRequiringPassphrase();
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();
-
bool StartRPC();
void InterruptRPC();
void StopRPC();
std::string JSONRPCExecBatch(const UniValue& vReq);
-void RPCNotifyBlockChange(bool ibd, const CBlockIndex *);
// Retrieves any serialization flags requested in command line argument
int RPCSerializationFlags();
diff --git a/src/scheduler.cpp b/src/scheduler.cpp
index b01170074d..4edb2c6d9b 100644
--- a/src/scheduler.cpp
+++ b/src/scheduler.cpp
@@ -4,6 +4,7 @@
#include "scheduler.h"
+#include "random.h"
#include "reverselock.h"
#include <assert.h>
@@ -23,7 +24,9 @@ CScheduler::~CScheduler()
#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));
+ // Creating the posix_time using from_time_t loses sub-second precision. So rather than exporting the time_point to time_t,
+ // start with a posix_time at the epoch (0) and add the milliseconds that have passed since then.
+ return boost::posix_time::from_time_t(0) + boost::posix_time::milliseconds(boost::chrono::duration_cast<boost::chrono::milliseconds>(t.time_since_epoch()).count());
}
#endif
@@ -37,6 +40,11 @@ void CScheduler::serviceQueue()
// is called.
while (!shouldStop()) {
try {
+ if (!shouldStop() && taskQueue.empty()) {
+ reverse_lock<boost::unique_lock<boost::mutex> > rlock(lock);
+ // Use this chance to get a tiny bit more entropy
+ RandAddSeedSleep();
+ }
while (!shouldStop() && taskQueue.empty()) {
// Wait until there is something to do.
newTaskScheduled.wait(lock);
@@ -104,20 +112,20 @@ void CScheduler::schedule(CScheduler::Function f, boost::chrono::system_clock::t
newTaskScheduled.notify_one();
}
-void CScheduler::scheduleFromNow(CScheduler::Function f, int64_t deltaSeconds)
+void CScheduler::scheduleFromNow(CScheduler::Function f, int64_t deltaMilliSeconds)
{
- schedule(f, boost::chrono::system_clock::now() + boost::chrono::seconds(deltaSeconds));
+ schedule(f, boost::chrono::system_clock::now() + boost::chrono::milliseconds(deltaMilliSeconds));
}
-static void Repeat(CScheduler* s, CScheduler::Function f, int64_t deltaSeconds)
+static void Repeat(CScheduler* s, CScheduler::Function f, int64_t deltaMilliSeconds)
{
f();
- s->scheduleFromNow(boost::bind(&Repeat, s, f, deltaSeconds), deltaSeconds);
+ s->scheduleFromNow(boost::bind(&Repeat, s, f, deltaMilliSeconds), deltaMilliSeconds);
}
-void CScheduler::scheduleEvery(CScheduler::Function f, int64_t deltaSeconds)
+void CScheduler::scheduleEvery(CScheduler::Function f, int64_t deltaMilliSeconds)
{
- scheduleFromNow(boost::bind(&Repeat, this, f, deltaSeconds), deltaSeconds);
+ scheduleFromNow(boost::bind(&Repeat, this, f, deltaMilliSeconds), deltaMilliSeconds);
}
size_t CScheduler::getQueueInfo(boost::chrono::system_clock::time_point &first,
@@ -131,3 +139,70 @@ size_t CScheduler::getQueueInfo(boost::chrono::system_clock::time_point &first,
}
return result;
}
+
+bool CScheduler::AreThreadsServicingQueue() const {
+ boost::unique_lock<boost::mutex> lock(newTaskMutex);
+ return nThreadsServicingQueue;
+}
+
+
+void SingleThreadedSchedulerClient::MaybeScheduleProcessQueue() {
+ {
+ LOCK(m_cs_callbacks_pending);
+ // Try to avoid scheduling too many copies here, but if we
+ // accidentally have two ProcessQueue's scheduled at once its
+ // not a big deal.
+ if (m_are_callbacks_running) return;
+ if (m_callbacks_pending.empty()) return;
+ }
+ m_pscheduler->schedule(std::bind(&SingleThreadedSchedulerClient::ProcessQueue, this));
+}
+
+void SingleThreadedSchedulerClient::ProcessQueue() {
+ std::function<void (void)> callback;
+ {
+ LOCK(m_cs_callbacks_pending);
+ if (m_are_callbacks_running) return;
+ if (m_callbacks_pending.empty()) return;
+ m_are_callbacks_running = true;
+
+ callback = std::move(m_callbacks_pending.front());
+ m_callbacks_pending.pop_front();
+ }
+
+ // RAII the setting of fCallbacksRunning and calling MaybeScheduleProcessQueue
+ // to ensure both happen safely even if callback() throws.
+ struct RAIICallbacksRunning {
+ SingleThreadedSchedulerClient* instance;
+ explicit RAIICallbacksRunning(SingleThreadedSchedulerClient* _instance) : instance(_instance) {}
+ ~RAIICallbacksRunning() {
+ {
+ LOCK(instance->m_cs_callbacks_pending);
+ instance->m_are_callbacks_running = false;
+ }
+ instance->MaybeScheduleProcessQueue();
+ }
+ } raiicallbacksrunning(this);
+
+ callback();
+}
+
+void SingleThreadedSchedulerClient::AddToProcessQueue(std::function<void (void)> func) {
+ assert(m_pscheduler);
+
+ {
+ LOCK(m_cs_callbacks_pending);
+ m_callbacks_pending.emplace_back(std::move(func));
+ }
+ MaybeScheduleProcessQueue();
+}
+
+void SingleThreadedSchedulerClient::EmptyQueue() {
+ assert(!m_pscheduler->AreThreadsServicingQueue());
+ bool should_continue = true;
+ while (should_continue) {
+ ProcessQueue();
+ LOCK(m_cs_callbacks_pending);
+ should_continue = !m_callbacks_pending.empty();
+ }
+}
diff --git a/src/scheduler.h b/src/scheduler.h
index 436659e58b..db93bcb21e 100644
--- a/src/scheduler.h
+++ b/src/scheduler.h
@@ -7,14 +7,15 @@
//
// NOTE:
-// boost::thread / boost::function / boost::chrono should be ported to
-// std::thread / std::function / std::chrono when we support C++11.
+// boost::thread / boost::chrono should be ported to std::thread / std::chrono
+// when we support C++11.
//
-#include <boost/function.hpp>
#include <boost/chrono/chrono.hpp>
#include <boost/thread.hpp>
#include <map>
+#include "sync.h"
+
//
// Simple class for background tasks that should be run
// periodically or once "after a while"
@@ -23,7 +24,7 @@
//
// CScheduler* s = new CScheduler();
// s->scheduleFromNow(doSomething, 11); // Assuming a: void doSomething() { }
-// s->scheduleFromNow(boost::bind(Class::func, this, argument), 3);
+// s->scheduleFromNow(std::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:
@@ -39,20 +40,20 @@ public:
CScheduler();
~CScheduler();
- typedef boost::function<void(void)> Function;
+ typedef std::function<void(void)> Function;
// Call func at/after time t
- void schedule(Function f, boost::chrono::system_clock::time_point t);
+ void schedule(Function f, boost::chrono::system_clock::time_point t=boost::chrono::system_clock::now());
// Convenience method: call f once deltaSeconds from now
- void scheduleFromNow(Function f, int64_t deltaSeconds);
+ void scheduleFromNow(Function f, int64_t deltaMilliSeconds);
// 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);
+ void scheduleEvery(Function f, int64_t deltaMilliSeconds);
// To keep things as simple as possible, there is no unschedule.
@@ -70,6 +71,9 @@ public:
size_t getQueueInfo(boost::chrono::system_clock::time_point &first,
boost::chrono::system_clock::time_point &last) const;
+ // Returns true if there are threads actively running in serviceQueue()
+ bool AreThreadsServicingQueue() const;
+
private:
std::multimap<boost::chrono::system_clock::time_point, Function> taskQueue;
boost::condition_variable newTaskScheduled;
@@ -77,7 +81,33 @@ private:
int nThreadsServicingQueue;
bool stopRequested;
bool stopWhenEmpty;
- bool shouldStop() { return stopRequested || (stopWhenEmpty && taskQueue.empty()); }
+ bool shouldStop() const { return stopRequested || (stopWhenEmpty && taskQueue.empty()); }
+};
+
+/**
+ * Class used by CScheduler clients which may schedule multiple jobs
+ * which are required to be run serially. Does not require such jobs
+ * to be executed on the same thread, but no two jobs will be executed
+ * at the same time.
+ */
+class SingleThreadedSchedulerClient {
+private:
+ CScheduler *m_pscheduler;
+
+ CCriticalSection m_cs_callbacks_pending;
+ std::list<std::function<void (void)>> m_callbacks_pending;
+ bool m_are_callbacks_running = false;
+
+ void MaybeScheduleProcessQueue();
+ void ProcessQueue();
+
+public:
+ explicit SingleThreadedSchedulerClient(CScheduler *pschedulerIn) : m_pscheduler(pschedulerIn) {}
+ void AddToProcessQueue(std::function<void (void)> func);
+
+ // Processes all remaining queue members on the calling thread, blocking until queue is empty
+ // Must be called after the CScheduler has no remaining processing threads!
+ void EmptyQueue();
};
#endif
diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp
index c4ab441e2c..03128917fd 100644
--- a/src/script/bitcoinconsensus.cpp
+++ b/src/script/bitcoinconsensus.cpp
@@ -28,10 +28,10 @@ public:
if (nSize > m_remaining)
throw std::ios_base::failure(std::string(__func__) + ": end of data");
- if (pch == NULL)
+ if (pch == nullptr)
throw std::ios_base::failure(std::string(__func__) + ": bad destination buffer");
- if (m_data == NULL)
+ if (m_data == nullptr)
throw std::ios_base::failure(std::string(__func__) + ": bad source buffer");
memcpy(pch, m_data, nSize);
@@ -68,7 +68,7 @@ struct ECCryptoClosure
};
ECCryptoClosure instance_of_eccryptoclosure;
-}
+} // namespace
/** Check that all specified flags are part of the libconsensus interface. */
static bool verify_flags(unsigned int flags)
@@ -95,7 +95,7 @@ static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptP
set_error(err, bitcoinconsensus_ERR_OK);
PrecomputedTransactionData txdata(tx);
- return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), &tx.vin[nIn].scriptWitness, flags, TransactionSignatureChecker(&tx, nIn, amount, txdata), NULL);
+ return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), &tx.vin[nIn].scriptWitness, flags, TransactionSignatureChecker(&tx, nIn, amount, txdata), nullptr);
} catch (const std::exception&) {
return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing
}
diff --git a/src/script/bitcoinconsensus.h b/src/script/bitcoinconsensus.h
index 1bef4fe9e9..33bf80e5a7 100644
--- a/src/script/bitcoinconsensus.h
+++ b/src/script/bitcoinconsensus.h
@@ -63,7 +63,7 @@ enum
/// Returns 1 if the input nIn of the serialized transaction pointed to by
/// txTo correctly spends the scriptPubKey pointed to by scriptPubKey under
/// the additional constraints specified by flags.
-/// If not NULL, err will contain an error/success code for the operation
+/// If not nullptr, err will contain an error/success code for the operation
EXPORT_SYMBOL int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
const unsigned char *txTo , unsigned int txToLen,
unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err);
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 7d5d2092f8..2f7b8e3a03 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -13,9 +13,7 @@
#include "script/script.h"
#include "uint256.h"
-using namespace std;
-
-typedef vector<unsigned char> valtype;
+typedef std::vector<unsigned char> valtype;
namespace {
@@ -33,7 +31,7 @@ inline bool set_error(ScriptError* ret, const ScriptError serror)
return false;
}
-} // anon namespace
+} // namespace
bool CastToBool(const valtype& vch)
{
@@ -56,10 +54,10 @@ bool CastToBool(const valtype& vch)
*/
#define stacktop(i) (stack.at(stack.size()+(i)))
#define altstacktop(i) (altstack.at(altstack.size()+(i)))
-static inline void popstack(vector<valtype>& stack)
+static inline void popstack(std::vector<valtype>& stack)
{
if (stack.empty())
- throw runtime_error("popstack(): stack empty");
+ throw std::runtime_error("popstack(): stack empty");
stack.pop_back();
}
@@ -194,7 +192,7 @@ bool static IsDefinedHashtypeSignature(const valtype &vchSig) {
return true;
}
-bool CheckSignatureEncoding(const vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror) {
+bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror) {
// Empty signature. Not strictly DER encoded, but allowed to provide a
// compact way to provide an invalid signature for use with CHECK(MULTI)SIG
if (vchSig.size() == 0) {
@@ -245,14 +243,14 @@ bool static CheckMinimalPush(const valtype& data, opcodetype opcode) {
return true;
}
-bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror)
+bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror)
{
static const CScriptNum bnZero(0);
static const CScriptNum bnOne(1);
- static const CScriptNum bnFalse(0);
- static const CScriptNum bnTrue(1);
+ // static const CScriptNum bnFalse(0);
+ // static const CScriptNum bnTrue(1);
static const valtype vchFalse(0);
- static const valtype vchZero(0);
+ // static const valtype vchZero(0);
static const valtype vchTrue(1, 1);
CScript::const_iterator pc = script.begin();
@@ -260,8 +258,8 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
CScript::const_iterator pbegincodehash = script.begin();
opcodetype opcode;
valtype vchPushValue;
- vector<bool> vfExec;
- vector<valtype> altstack;
+ std::vector<bool> vfExec;
+ std::vector<valtype> altstack;
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
if (script.size() > MAX_SCRIPT_SIZE)
return set_error(serror, SCRIPT_ERR_SCRIPT_SIZE);
@@ -1030,7 +1028,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
}
// Size limits
- if (stack.size() + altstack.size() > 1000)
+ if (stack.size() + altstack.size() > MAX_STACK_SIZE)
return set_error(serror, SCRIPT_ERR_STACK_SIZE);
}
}
@@ -1101,7 +1099,7 @@ public:
// Serialize the script
if (nInput != nIn)
// Blank out other inputs' signatures
- ::Serialize(s, CScriptBase());
+ ::Serialize(s, CScript());
else
SerializeScriptCode(s);
// Serialize the nSequence
@@ -1144,29 +1142,29 @@ public:
uint256 GetPrevoutHash(const CTransaction& txTo) {
CHashWriter ss(SER_GETHASH, 0);
- for (unsigned int n = 0; n < txTo.vin.size(); n++) {
- ss << txTo.vin[n].prevout;
+ for (const auto& txin : txTo.vin) {
+ ss << txin.prevout;
}
return ss.GetHash();
}
uint256 GetSequenceHash(const CTransaction& txTo) {
CHashWriter ss(SER_GETHASH, 0);
- for (unsigned int n = 0; n < txTo.vin.size(); n++) {
- ss << txTo.vin[n].nSequence;
+ for (const auto& txin : txTo.vin) {
+ ss << txin.nSequence;
}
return ss.GetHash();
}
uint256 GetOutputsHash(const CTransaction& txTo) {
CHashWriter ss(SER_GETHASH, 0);
- for (unsigned int n = 0; n < txTo.vout.size(); n++) {
- ss << txTo.vout[n];
+ for (const auto& txout : txTo.vout) {
+ ss << txout;
}
return ss.GetHash();
}
-} // anon namespace
+} // namespace
PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)
{
@@ -1181,6 +1179,8 @@ PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)
uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
{
+ assert(nIn < txTo.vin.size());
+
if (sigversion == SIGVERSION_WITNESS_V0) {
uint256 hashPrevouts;
uint256 hashSequence;
@@ -1214,7 +1214,7 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig
// The prevout may already be contained in hashPrevout, and the nSequence
// may already be contain in hashSequence.
ss << txTo.vin[nIn].prevout;
- ss << static_cast<const CScriptBase&>(scriptCode);
+ ss << scriptCode;
ss << amount;
ss << txTo.vin[nIn].nSequence;
// Outputs (none/one/all, depending on flags)
@@ -1228,10 +1228,6 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig
}
static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
- if (nIn >= txTo.vin.size()) {
- // nIn out of range
- return one;
- }
// Check for invalid use of SIGHASH_SINGLE
if ((nHashType & 0x1f) == SIGHASH_SINGLE) {
@@ -1255,14 +1251,14 @@ bool TransactionSignatureChecker::VerifySignature(const std::vector<unsigned cha
return pubkey.Verify(sighash, vchSig);
}
-bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
+bool TransactionSignatureChecker::CheckSig(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
{
CPubKey pubkey(vchPubKey);
if (!pubkey.IsValid())
return false;
// Hash type is one byte tacked on to the end of the signature
- vector<unsigned char> vchSig(vchSigIn);
+ std::vector<unsigned char> vchSig(vchSigIn);
if (vchSig.empty())
return false;
int nHashType = vchSig.back();
@@ -1360,7 +1356,7 @@ bool TransactionSignatureChecker::CheckSequence(const CScriptNum& nSequence) con
static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
{
- vector<vector<unsigned char> > stack;
+ std::vector<std::vector<unsigned char> > stack;
CScript scriptPubKey;
if (witversion == 0) {
@@ -1373,7 +1369,7 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion,
stack = std::vector<std::vector<unsigned char> >(witness.stack.begin(), witness.stack.end() - 1);
uint256 hashScriptPubKey;
CSHA256().Write(&scriptPubKey[0], scriptPubKey.size()).Finalize(hashScriptPubKey.begin());
- if (memcmp(hashScriptPubKey.begin(), &program[0], 32)) {
+ if (memcmp(hashScriptPubKey.begin(), program.data(), 32)) {
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
}
} else if (program.size() == 20) {
@@ -1414,7 +1410,7 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion,
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
{
static const CScriptWitness emptyWitness;
- if (witness == NULL) {
+ if (witness == nullptr) {
witness = &emptyWitness;
}
bool hadWitness = false;
@@ -1425,7 +1421,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY);
}
- vector<vector<unsigned char> > stack, stackCopy;
+ std::vector<std::vector<unsigned char> > stack, stackCopy;
if (!EvalScript(stack, scriptSig, flags, checker, SIGVERSION_BASE, serror))
// serror is set
return false;
@@ -1563,7 +1559,7 @@ size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey,
if (scriptPubKey.IsPayToScriptHash() && scriptSig.IsPushOnly()) {
CScript::const_iterator pc = scriptSig.begin();
- vector<unsigned char> data;
+ std::vector<unsigned char> data;
while (pc < scriptSig.end()) {
opcodetype opcode;
scriptSig.GetOp(pc, opcode, data);
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index c6385cb519..1cb9cc7899 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -115,7 +115,7 @@ struct PrecomputedTransactionData
uint256 hashPrevouts, hashSequence, hashOutputs;
bool ready = false;
- PrecomputedTransactionData(const CTransaction& tx);
+ explicit PrecomputedTransactionData(const CTransaction& tx);
};
enum SigVersion
@@ -124,7 +124,7 @@ enum SigVersion
SIGVERSION_WITNESS_V0 = 1,
};
-uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = NULL);
+uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr);
class BaseSignatureChecker
{
@@ -159,11 +159,11 @@ protected:
virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
public:
- TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(NULL) {}
+ TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(nullptr) {}
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
- bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const;
- bool CheckLockTime(const CScriptNum& nLockTime) const;
- bool CheckSequence(const CScriptNum& nSequence) const;
+ bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override;
+ bool CheckLockTime(const CScriptNum& nLockTime) const override;
+ bool CheckSequence(const CScriptNum& nSequence) const override;
};
class MutableTransactionSignatureChecker : public TransactionSignatureChecker
@@ -172,11 +172,11 @@ private:
const CTransaction txTo;
public:
- MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount) : TransactionSignatureChecker(&txTo, nInIn, amount), txTo(*txToIn) {}
+ MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : TransactionSignatureChecker(&txTo, nInIn, amountIn), txTo(*txToIn) {}
};
-bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = NULL);
-bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror = NULL);
+bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = nullptr);
+bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror = nullptr);
size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags);
diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp
index 608a8de8f5..6b68f0679e 100644
--- a/src/script/ismine.cpp
+++ b/src/script/ismine.cpp
@@ -11,16 +11,13 @@
#include "script/standard.h"
#include "script/sign.h"
-#include <boost/foreach.hpp>
-using namespace std;
+typedef std::vector<unsigned char> valtype;
-typedef vector<unsigned char> valtype;
-
-unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore)
+unsigned int HaveKeys(const std::vector<valtype>& pubkeys, const CKeyStore& keystore)
{
unsigned int nResult = 0;
- BOOST_FOREACH(const valtype& pubkey, pubkeys)
+ for (const valtype& pubkey : pubkeys)
{
CKeyID keyID = CPubKey(pubkey).GetID();
if (keystore.HaveKey(keyID))
@@ -49,7 +46,9 @@ isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest, bool& i
isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool& isInvalid, SigVersion sigversion)
{
- vector<valtype> vSolutions;
+ isInvalid = false;
+
+ std::vector<valtype> vSolutions;
txnouttype whichType;
if (!Solver(scriptPubKey, whichType, vSolutions)) {
if (keystore.HaveWatchOnly(scriptPubKey))
@@ -62,6 +61,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool&
{
case TX_NONSTANDARD:
case TX_NULL_DATA:
+ case TX_WITNESS_UNKNOWN:
break;
case TX_PUBKEY:
keyID = CPubKey(vSolutions[0]).GetID();
@@ -132,7 +132,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool&
// partially owned (somebody else has a key that can spend
// them) enable spend-out-from-under-you attacks, especially
// in shared-wallet situations.
- vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
+ std::vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
if (sigversion != SIGVERSION_BASE) {
for (size_t i = 0; i < keys.size(); i++) {
if (keys[i].size() != 33) {
diff --git a/src/script/script.cpp b/src/script/script.cpp
index 828ce1a056..a10b619f7d 100644
--- a/src/script/script.cpp
+++ b/src/script/script.cpp
@@ -8,8 +8,6 @@
#include "tinyformat.h"
#include "utilstrencodings.h"
-using namespace std;
-
const char* GetOpName(opcodetype opcode)
{
switch (opcode)
@@ -129,7 +127,7 @@ const char* GetOpName(opcodetype opcode)
case OP_CHECKMULTISIG : return "OP_CHECKMULTISIG";
case OP_CHECKMULTISIGVERIFY : return "OP_CHECKMULTISIGVERIFY";
- // expanson
+ // expansion
case OP_NOP1 : return "OP_NOP1";
case OP_CHECKLOCKTIMEVERIFY : return "OP_CHECKLOCKTIMEVERIFY";
case OP_CHECKSEQUENCEVERIFY : return "OP_CHECKSEQUENCEVERIFY";
@@ -186,18 +184,18 @@ unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const
// get the last item that the scriptSig
// pushes onto the stack:
const_iterator pc = scriptSig.begin();
- vector<unsigned char> data;
+ std::vector<unsigned char> vData;
while (pc < scriptSig.end())
{
opcodetype opcode;
- if (!scriptSig.GetOp(pc, opcode, data))
+ if (!scriptSig.GetOp(pc, opcode, vData))
return 0;
if (opcode > OP_16)
return 0;
}
/// ... and return its opcount:
- CScript subscript(data.begin(), data.end());
+ CScript subscript(vData.begin(), vData.end());
return subscript.GetSigOpCount(true);
}
@@ -269,3 +267,16 @@ std::string CScriptWitness::ToString() const
}
return ret + ")";
}
+
+bool CScript::HasValidOps() const
+{
+ CScript::const_iterator it = begin();
+ while (it < end()) {
+ opcodetype opcode;
+ std::vector<unsigned char> item;
+ if (!GetOp(it, opcode, item) || opcode > MAX_OPCODE || item.size() > MAX_SCRIPT_ELEMENT_SIZE) {
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/src/script/script.h b/src/script/script.h
index 654dff4625..2a92060543 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -8,6 +8,7 @@
#include "crypto/common.h"
#include "prevector.h"
+#include "serialize.h"
#include <assert.h>
#include <climits>
@@ -30,6 +31,9 @@ static const int MAX_PUBKEYS_PER_MULTISIG = 20;
// Maximum script length in bytes
static const int MAX_SCRIPT_SIZE = 10000;
+// Maximum number of values on script interpreter stack
+static const int MAX_STACK_SIZE = 1000;
+
// 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
@@ -187,6 +191,9 @@ enum opcodetype
OP_INVALIDOPCODE = 0xff,
};
+// Maximum value that an opcode can be
+static const unsigned int MAX_OPCODE = OP_NOP10;
+
const char* GetOpName(opcodetype opcode);
class scriptnum_error : public std::runtime_error
@@ -370,6 +377,12 @@ private:
int64_t m_value;
};
+/**
+ * We use a prevector for the script to reduce the considerable memory overhead
+ * of vectors in cases where they normally contain a small number of small elements.
+ * Tests in October 2015 showed use of this reduced dbcache memory usage by 23%
+ * and made an initial sync 13% faster.
+ */
typedef prevector<28, unsigned char> CScriptBase;
/** Serialized script, used inside transaction inputs and outputs */
@@ -398,8 +411,16 @@ public:
CScript(std::vector<unsigned char>::const_iterator pbegin, std::vector<unsigned char>::const_iterator pend) : CScriptBase(pbegin, pend) { }
CScript(const unsigned char* pbegin, const unsigned char* pend) : CScriptBase(pbegin, pend) { }
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action) {
+ READWRITE(static_cast<CScriptBase&>(*this));
+ }
+
CScript& operator+=(const CScript& b)
{
+ reserve(size() + b.size());
insert(end(), b.begin(), b.end());
return *this;
}
@@ -448,16 +469,16 @@ public:
else if (b.size() <= 0xffff)
{
insert(end(), OP_PUSHDATA2);
- uint8_t data[2];
- WriteLE16(data, b.size());
- insert(end(), data, data + sizeof(data));
+ uint8_t _data[2];
+ WriteLE16(_data, b.size());
+ insert(end(), _data, _data + sizeof(_data));
}
else
{
insert(end(), OP_PUSHDATA4);
- uint8_t data[4];
- WriteLE32(data, b.size());
- insert(end(), data, data + sizeof(data));
+ uint8_t _data[4];
+ WriteLE32(_data, b.size());
+ insert(end(), _data, _data + sizeof(_data));
}
insert(end(), b.begin(), b.end());
return *this;
@@ -484,7 +505,7 @@ public:
bool GetOp(iterator& pc, opcodetype& opcodeRet)
{
const_iterator pc2 = pc;
- bool fRet = GetOp2(pc2, opcodeRet, NULL);
+ bool fRet = GetOp2(pc2, opcodeRet, nullptr);
pc = begin() + (pc2 - begin());
return fRet;
}
@@ -496,7 +517,7 @@ public:
bool GetOp(const_iterator& pc, opcodetype& opcodeRet) const
{
- return GetOp2(pc, opcodeRet, NULL);
+ return GetOp2(pc, opcodeRet, nullptr);
}
bool GetOp2(const_iterator& pc, opcodetype& opcodeRet, std::vector<unsigned char>* pvchRet) const
@@ -627,6 +648,9 @@ public:
bool IsPushOnly(const_iterator pc) const;
bool IsPushOnly() const;
+ /** Check if the script contains valid OP_CODES */
+ bool HasValidOps() const;
+
/**
* Returns whether the script is guaranteed to fail at execution,
* regardless of the initial stack. This allows outputs to be pruned
@@ -639,8 +663,9 @@ public:
void clear()
{
- // The default std::vector::clear() does not release memory.
- CScriptBase().swap(*this);
+ // The default prevector::clear() does not release memory
+ CScriptBase::clear();
+ shrink_to_fit();
}
};
diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp
index c9d13c92a8..6c590f53e3 100644
--- a/src/script/script_error.cpp
+++ b/src/script/script_error.cpp
@@ -73,6 +73,8 @@ const char* ScriptErrorString(const ScriptError serror)
return "Witness version reserved for soft-fork upgrades";
case SCRIPT_ERR_PUBKEYTYPE:
return "Public key is neither compressed or uncompressed";
+ case SCRIPT_ERR_CLEANSTACK:
+ return "Extra items left on stack after execution";
case SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH:
return "Witness program has incorrect length";
case SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY:
diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp
index 09bedc5460..4cc7afa2f5 100644
--- a/src/script/sigcache.cpp
+++ b/src/script/sigcache.cpp
@@ -15,28 +15,6 @@
#include <boost/thread.hpp>
namespace {
-
-/**
- * We're hashing a nonce into the entries themselves, so we don't need extra
- * blinding in the set hash computation.
- *
- * This may exhibit platform endian dependent behavior but because these are
- * nonced hashes (random) and this state is only ever used locally it is safe.
- * All that matters is local consistency.
- */
-class SignatureCacheHasher
-{
-public:
- template <uint8_t hash_select>
- uint32_t operator()(const uint256& key) const
- {
- static_assert(hash_select <8, "SignatureCacheHasher only has 8 hashes available.");
- uint32_t u;
- std::memcpy(&u, key.begin()+4*hash_select, 4);
- return u;
- }
-};
-
/**
* Valid signature cache, to avoid doing expensive ECDSA signature checking
* twice for every transaction (once when accepted into memory pool, and
@@ -88,16 +66,18 @@ public:
* signatureCache could be made local to VerifySignature.
*/
static CSignatureCache signatureCache;
-}
+} // namespace
-// To be called once in AppInit2/TestingSetup to initialize the signatureCache
+// To be called once in AppInitMain/BasicTestingSetup to initialize the
+// signatureCache.
void InitSignatureCache()
{
- size_t nMaxCacheSize = GetArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20);
- if (nMaxCacheSize <= 0) return;
+ // nMaxCacheSize is unsigned. If -maxsigcachesize is set to zero,
+ // setup_bytes creates the minimum possible cache (2 elements).
+ size_t nMaxCacheSize = std::min(std::max((int64_t)0, gArgs.GetArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE) / 2), MAX_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20);
size_t nElems = signatureCache.setup_bytes(nMaxCacheSize);
- LogPrintf("Using %zu MiB out of %zu requested for signature cache, able to store %zu elements\n",
- (nElems*sizeof(uint256)) >>20, nMaxCacheSize>>20, nElems);
+ LogPrintf("Using %zu MiB out of %zu/2 requested for signature cache, able to store %zu elements\n",
+ (nElems*sizeof(uint256)) >>20, (nMaxCacheSize*2)>>20, nElems);
}
bool CachingTransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
diff --git a/src/script/sigcache.h b/src/script/sigcache.h
index c123a9ba0f..5832b264b3 100644
--- a/src/script/sigcache.h
+++ b/src/script/sigcache.h
@@ -14,18 +14,41 @@
// systems). Due to how we count cache size, actual memory usage is slightly
// more (~32.25 MB)
static const unsigned int DEFAULT_MAX_SIG_CACHE_SIZE = 32;
+// Maximum sig cache size allowed
+static const int64_t MAX_MAX_SIG_CACHE_SIZE = 16384;
class CPubKey;
+/**
+ * We're hashing a nonce into the entries themselves, so we don't need extra
+ * blinding in the set hash computation.
+ *
+ * This may exhibit platform endian dependent behavior but because these are
+ * nonced hashes (random) and this state is only ever used locally it is safe.
+ * All that matters is local consistency.
+ */
+class SignatureCacheHasher
+{
+public:
+ template <uint8_t hash_select>
+ uint32_t operator()(const uint256& key) const
+ {
+ static_assert(hash_select <8, "SignatureCacheHasher only has 8 hashes available.");
+ uint32_t u;
+ std::memcpy(&u, key.begin()+4*hash_select, 4);
+ return u;
+ }
+};
+
class CachingTransactionSignatureChecker : public TransactionSignatureChecker
{
private:
bool store;
public:
- CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amount, txdataIn), store(storeIn) {}
+ CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amountIn, txdataIn), store(storeIn) {}
- bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
+ bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const override;
};
void InitSignatureCache();
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index b008df2591..ac58b690a2 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -12,9 +12,6 @@
#include "script/standard.h"
#include "uint256.h"
-#include <boost/foreach.hpp>
-
-using namespace std;
typedef std::vector<unsigned char> valtype;
@@ -39,14 +36,14 @@ bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig,
static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, SigVersion sigversion)
{
- vector<unsigned char> vchSig;
+ std::vector<unsigned char> vchSig;
if (!creator.CreateSig(vchSig, address, scriptCode, sigversion))
return false;
ret.push_back(vchSig);
return true;
}
-static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, SigVersion sigversion)
+static bool SignN(const std::vector<valtype>& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, SigVersion sigversion)
{
int nSigned = 0;
int nRequired = multisigdata.front()[0];
@@ -73,7 +70,7 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP
uint160 h160;
ret.clear();
- vector<valtype> vSolutions;
+ std::vector<valtype> vSolutions;
if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
return false;
@@ -82,6 +79,7 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP
{
case TX_NONSTANDARD:
case TX_NULL_DATA:
+ case TX_WITNESS_UNKNOWN:
return false;
case TX_PUBKEY:
keyID = CPubKey(vSolutions[0]).GetID();
@@ -125,10 +123,10 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP
}
}
-static CScript PushAll(const vector<valtype>& values)
+static CScript PushAll(const std::vector<valtype>& values)
{
CScript result;
- BOOST_FOREACH(const valtype& v, values) {
+ for (const valtype& v : values) {
if (v.size() == 0) {
result << OP_0;
} else if (v.size() == 1 && v[0] >= 1 && v[0] <= 16) {
@@ -143,10 +141,9 @@ static CScript PushAll(const vector<valtype>& values)
bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, SignatureData& sigdata)
{
CScript script = fromPubKey;
- bool solved = true;
std::vector<valtype> result;
txnouttype whichType;
- solved = SignStep(creator, script, result, whichType, SIGVERSION_BASE);
+ bool solved = SignStep(creator, script, result, whichType, SIGVERSION_BASE);
bool P2SH = false;
CScript subscript;
sigdata.scriptWitness.stack.clear();
@@ -228,18 +225,18 @@ bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutab
return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType);
}
-static vector<valtype> CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
- const vector<valtype>& vSolutions,
- const vector<valtype>& sigs1, const vector<valtype>& sigs2, SigVersion sigversion)
+static std::vector<valtype> CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
+ const std::vector<valtype>& vSolutions,
+ const std::vector<valtype>& sigs1, const std::vector<valtype>& sigs2, SigVersion sigversion)
{
// Combine all the signatures we've got:
- set<valtype> allsigs;
- BOOST_FOREACH(const valtype& v, sigs1)
+ std::set<valtype> allsigs;
+ for (const valtype& v : sigs1)
{
if (!v.empty())
allsigs.insert(v);
}
- BOOST_FOREACH(const valtype& v, sigs2)
+ for (const valtype& v : sigs2)
{
if (!v.empty())
allsigs.insert(v);
@@ -249,8 +246,8 @@ static vector<valtype> CombineMultisig(const CScript& scriptPubKey, const BaseSi
assert(vSolutions.size() > 1);
unsigned int nSigsRequired = vSolutions.front()[0];
unsigned int nPubKeys = vSolutions.size()-2;
- map<valtype, valtype> sigs;
- BOOST_FOREACH(const valtype& sig, allsigs)
+ std::map<valtype, valtype> sigs;
+ for (const valtype& sig : allsigs)
{
for (unsigned int i = 0; i < nPubKeys; i++)
{
@@ -306,13 +303,14 @@ struct Stacks
}
static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
- const txnouttype txType, const vector<valtype>& vSolutions,
+ const txnouttype txType, const std::vector<valtype>& vSolutions,
Stacks sigs1, Stacks sigs2, SigVersion sigversion)
{
switch (txType)
{
case TX_NONSTANDARD:
case TX_NULL_DATA:
+ case TX_WITNESS_UNKNOWN:
// Don't know anything about this, assume bigger one is correct:
if (sigs1.script.size() >= sigs2.script.size())
return sigs1;
@@ -340,7 +338,7 @@ static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignature
CScript pubKey2(spk.begin(), spk.end());
txnouttype txType2;
- vector<vector<unsigned char> > vSolutions2;
+ std::vector<std::vector<unsigned char> > vSolutions2;
Solver(pubKey2, txType2, vSolutions2);
sigs1.script.pop_back();
sigs2.script.pop_back();
@@ -360,7 +358,7 @@ static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignature
// Recur to combine:
CScript pubKey2(sigs1.witness.back().begin(), sigs1.witness.back().end());
txnouttype txType2;
- vector<valtype> vSolutions2;
+ std::vector<valtype> vSolutions2;
Solver(pubKey2, txType2, vSolutions2);
sigs1.witness.pop_back();
sigs1.script = sigs1.witness;
@@ -383,7 +381,7 @@ SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignature
const SignatureData& scriptSig1, const SignatureData& scriptSig2)
{
txnouttype txType;
- vector<vector<unsigned char> > vSolutions;
+ std::vector<std::vector<unsigned char> > vSolutions;
Solver(scriptPubKey, txType, vSolutions);
return CombineSignatures(scriptPubKey, checker, txType, vSolutions, Stacks(scriptSig1), Stacks(scriptSig2), SIGVERSION_BASE).Output();
@@ -396,13 +394,13 @@ class DummySignatureChecker : public BaseSignatureChecker
public:
DummySignatureChecker() {}
- bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
+ bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override
{
return true;
}
};
const DummySignatureChecker dummyChecker;
-}
+} // namespace
const BaseSignatureChecker& DummySignatureCreator::Checker() const
{
diff --git a/src/script/sign.h b/src/script/sign.h
index 1cfc53c6c1..a0d8ee4ff9 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -21,7 +21,7 @@ protected:
const CKeyStore* keystore;
public:
- BaseSignatureCreator(const CKeyStore* keystoreIn) : keystore(keystoreIn) {}
+ explicit BaseSignatureCreator(const CKeyStore* keystoreIn) : keystore(keystoreIn) {}
const CKeyStore& KeyStore() const { return *keystore; };
virtual ~BaseSignatureCreator() {}
virtual const BaseSignatureChecker& Checker() const =0;
@@ -40,23 +40,23 @@ class TransactionSignatureCreator : public BaseSignatureCreator {
public:
TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn=SIGHASH_ALL);
- const BaseSignatureChecker& Checker() const { return checker; }
- bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const;
+ const BaseSignatureChecker& Checker() const override { return checker; }
+ bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override;
};
class MutableTransactionSignatureCreator : public TransactionSignatureCreator {
CTransaction tx;
public:
- MutableTransactionSignatureCreator(const CKeyStore* keystoreIn, const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount, int nHashTypeIn) : TransactionSignatureCreator(keystoreIn, &tx, nInIn, amount, nHashTypeIn), tx(*txToIn) {}
+ MutableTransactionSignatureCreator(const CKeyStore* keystoreIn, const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : TransactionSignatureCreator(keystoreIn, &tx, nInIn, amountIn, nHashTypeIn), tx(*txToIn) {}
};
/** A signature creator that just produces 72-byte empty signatures. */
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, SigVersion sigversion) const;
+ explicit DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {}
+ const BaseSignatureChecker& Checker() const override;
+ bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override;
};
struct SignatureData {
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index 4b9bec9aa1..f57f1f61b4 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -10,11 +10,8 @@
#include "util.h"
#include "utilstrencodings.h"
-#include <boost/foreach.hpp>
-using namespace std;
-
-typedef vector<unsigned char> valtype;
+typedef std::vector<unsigned char> valtype;
bool fAcceptDatacarrier = DEFAULT_ACCEPT_DATACARRIER;
unsigned nMaxDatacarrierBytes = MAX_OP_RETURN_RELAY;
@@ -33,27 +30,25 @@ const char* GetTxnOutputType(txnouttype t)
case TX_NULL_DATA: return "nulldata";
case TX_WITNESS_V0_KEYHASH: return "witness_v0_keyhash";
case TX_WITNESS_V0_SCRIPTHASH: return "witness_v0_scripthash";
+ case TX_WITNESS_UNKNOWN: return "witness_unknown";
}
- return NULL;
+ return nullptr;
}
-/**
- * Return public keys or hashes from scriptPubKey, for 'standard' transaction types.
- */
-bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsigned char> >& vSolutionsRet)
+bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet)
{
// Templates
- static multimap<txnouttype, CScript> mTemplates;
+ static std::multimap<txnouttype, CScript> mTemplates;
if (mTemplates.empty())
{
// Standard tx, sender provides pubkey, receiver adds signature
- mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG));
+ mTemplates.insert(std::make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG));
// Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey
- mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG));
+ mTemplates.insert(std::make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG));
// Sender provides N pubkeys, receivers provides M signatures
- mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
+ mTemplates.insert(std::make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
}
vSolutionsRet.clear();
@@ -63,7 +58,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
if (scriptPubKey.IsPayToScriptHash())
{
typeRet = TX_SCRIPTHASH;
- vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);
+ std::vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);
vSolutionsRet.push_back(hashBytes);
return true;
}
@@ -81,6 +76,12 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
vSolutionsRet.push_back(witnessprogram);
return true;
}
+ if (witnessversion != 0) {
+ typeRet = TX_WITNESS_UNKNOWN;
+ vSolutionsRet.push_back(std::vector<unsigned char>{(unsigned char)witnessversion});
+ vSolutionsRet.push_back(std::move(witnessprogram));
+ return true;
+ }
return false;
}
@@ -96,13 +97,13 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
// Scan templates
const CScript& script1 = scriptPubKey;
- BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates)
+ for (const std::pair<txnouttype, CScript>& tplate : mTemplates)
{
const CScript& script2 = tplate.second;
vSolutionsRet.clear();
opcodetype opcode1, opcode2;
- vector<unsigned char> vch1, vch2;
+ std::vector<unsigned char> vch1, vch2;
// Compare
CScript::const_iterator pc1 = script1.begin();
@@ -181,7 +182,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
{
- vector<valtype> vSolutions;
+ std::vector<valtype> vSolutions;
txnouttype whichType;
if (!Solver(scriptPubKey, whichType, vSolutions))
return false;
@@ -204,16 +205,33 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
{
addressRet = CScriptID(uint160(vSolutions[0]));
return true;
+ } else if (whichType == TX_WITNESS_V0_KEYHASH) {
+ WitnessV0KeyHash hash;
+ std::copy(vSolutions[0].begin(), vSolutions[0].end(), hash.begin());
+ addressRet = hash;
+ return true;
+ } else if (whichType == TX_WITNESS_V0_SCRIPTHASH) {
+ WitnessV0ScriptHash hash;
+ std::copy(vSolutions[0].begin(), vSolutions[0].end(), hash.begin());
+ addressRet = hash;
+ return true;
+ } else if (whichType == TX_WITNESS_UNKNOWN) {
+ WitnessUnknown unk;
+ unk.version = vSolutions[0][0];
+ std::copy(vSolutions[1].begin(), vSolutions[1].end(), unk.program);
+ unk.length = vSolutions[1].size();
+ addressRet = unk;
+ return true;
}
// Multisig txns have more than one address...
return false;
}
-bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vector<CTxDestination>& addressRet, int& nRequiredRet)
+bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet)
{
addressRet.clear();
typeRet = TX_NONSTANDARD;
- vector<valtype> vSolutions;
+ std::vector<valtype> vSolutions;
if (!Solver(scriptPubKey, typeRet, vSolutions))
return false;
if (typeRet == TX_NULL_DATA){
@@ -256,7 +274,7 @@ class CScriptVisitor : public boost::static_visitor<bool>
private:
CScript *script;
public:
- CScriptVisitor(CScript *scriptin) { script = scriptin; }
+ explicit CScriptVisitor(CScript *scriptin) { script = scriptin; }
bool operator()(const CNoDestination &dest) const {
script->clear();
@@ -274,8 +292,29 @@ public:
*script << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL;
return true;
}
+
+ bool operator()(const WitnessV0KeyHash& id) const
+ {
+ script->clear();
+ *script << OP_0 << ToByteVector(id);
+ return true;
+ }
+
+ bool operator()(const WitnessV0ScriptHash& id) const
+ {
+ script->clear();
+ *script << OP_0 << ToByteVector(id);
+ return true;
+ }
+
+ bool operator()(const WitnessUnknown& id) const
+ {
+ script->clear();
+ *script << CScript::EncodeOP_N(id.version) << std::vector<unsigned char>(id.program, id.program + id.length);
+ return true;
+ }
};
-}
+} // namespace
CScript GetScriptForDestination(const CTxDestination& dest)
{
@@ -295,7 +334,7 @@ CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)
CScript script;
script << CScript::EncodeOP_N(nRequired);
- BOOST_FOREACH(const CPubKey& key, keys)
+ for (const CPubKey& key : keys)
script << ToByteVector(key);
script << CScript::EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
return script;
@@ -323,3 +362,7 @@ CScript GetScriptForWitness(const CScript& redeemscript)
ret << OP_0 << ToByteVector(hash);
return ret;
}
+
+bool IsValidDestination(const CTxDestination& dest) {
+ return dest.which() != 0;
+}
diff --git a/src/script/standard.h b/src/script/standard.h
index 097e0c3748..fa07ea88c1 100644
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -27,8 +27,19 @@ public:
CScriptID(const uint160& in) : uint160(in) {}
};
-static const unsigned int MAX_OP_RETURN_RELAY = 83; //!< bytes (+1 for OP_RETURN, +2 for the pushdata opcodes)
+/**
+ * Default setting for nMaxDatacarrierBytes. 80 bytes of data, +1 for OP_RETURN,
+ * +2 for the pushdata opcodes.
+ */
+static const unsigned int MAX_OP_RETURN_RELAY = 83;
+
+/**
+ * A data carrying output is an unspendable output containing data. The script
+ * type is designated as TX_NULL_DATA.
+ */
extern bool fAcceptDatacarrier;
+
+/** Maximum size of TX_NULL_DATA scripts that this node considers standard. */
extern unsigned nMaxDatacarrierBytes;
/**
@@ -36,7 +47,7 @@ extern unsigned nMaxDatacarrierBytes;
* them to be valid. (but old blocks may not comply with) Currently just P2SH,
* but in the future other flags may be added, such as a soft-fork to enforce
* strict DER encoding.
- *
+ *
* Failing one of these tests may trigger a DoS ban - see CheckInputs() for
* details.
*/
@@ -50,9 +61,10 @@ enum txnouttype
TX_PUBKEYHASH,
TX_SCRIPTHASH,
TX_MULTISIG,
- TX_NULL_DATA,
+ TX_NULL_DATA, //!< unspendable OP_RETURN script that carries data
TX_WITNESS_V0_SCRIPTHASH,
TX_WITNESS_V0_KEYHASH,
+ TX_WITNESS_UNKNOWN, //!< Only for Witness versions not already defined above
};
class CNoDestination {
@@ -61,24 +73,98 @@ public:
friend bool operator<(const CNoDestination &a, const CNoDestination &b) { return true; }
};
-/**
+struct WitnessV0ScriptHash : public uint256 {};
+struct WitnessV0KeyHash : public uint160 {};
+
+//! CTxDestination subtype to encode any future Witness version
+struct WitnessUnknown
+{
+ unsigned int version;
+ unsigned int length;
+ unsigned char program[40];
+
+ friend bool operator==(const WitnessUnknown& w1, const WitnessUnknown& w2) {
+ if (w1.version != w2.version) return false;
+ if (w1.length != w2.length) return false;
+ return std::equal(w1.program, w1.program + w1.length, w2.program);
+ }
+
+ friend bool operator<(const WitnessUnknown& w1, const WitnessUnknown& w2) {
+ if (w1.version < w2.version) return true;
+ if (w1.version > w2.version) return false;
+ if (w1.length < w2.length) return true;
+ if (w1.length > w2.length) return false;
+ return std::lexicographical_compare(w1.program, w1.program + w1.length, w2.program, w2.program + w2.length);
+ }
+};
+
+/**
* A txout script template with a specific destination. It is either:
* * CNoDestination: no destination set
- * * CKeyID: TX_PUBKEYHASH destination
- * * CScriptID: TX_SCRIPTHASH destination
- * A CTxDestination is the internal data type encoded in a CBitcoinAddress
+ * * CKeyID: TX_PUBKEYHASH destination (P2PKH)
+ * * CScriptID: TX_SCRIPTHASH destination (P2SH)
+ * * WitnessV0ScriptHash: TX_WITNESS_V0_SCRIPTHASH destination (P2WSH)
+ * * WitnessV0KeyHash: TX_WITNESS_V0_KEYHASH destination (P2WPKH)
+ * * WitnessUnknown: TX_WITNESS_UNKNOWN destination (P2W???)
+ * A CTxDestination is the internal data type encoded in a bitcoin address
*/
-typedef boost::variant<CNoDestination, CKeyID, CScriptID> CTxDestination;
+typedef boost::variant<CNoDestination, CKeyID, CScriptID, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown> CTxDestination;
+/** Check whether a CTxDestination is a CNoDestination. */
+bool IsValidDestination(const CTxDestination& dest);
+
+/** Get the name of a txnouttype as a C string, or nullptr if unknown. */
const char* GetTxnOutputType(txnouttype t);
+/**
+ * Parse a scriptPubKey and identify script type for standard scripts. If
+ * successful, returns script type and parsed pubkeys or hashes, depending on
+ * the type. For example, for a P2SH script, vSolutionsRet will contain the
+ * script hash, for P2PKH it will contain the key hash, etc.
+ *
+ * @param[in] scriptPubKey Script to parse
+ * @param[out] typeRet The script type
+ * @param[out] vSolutionsRet Vector of parsed pubkeys and hashes
+ * @return True if script matches standard template
+ */
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
+
+/**
+ * Parse a standard scriptPubKey for the destination address. Assigns result to
+ * the addressRet parameter and returns true if successful. For multisig
+ * scripts, instead use ExtractDestinations. Currently only works for P2PK,
+ * P2PKH, P2SH, P2WPKH, and P2WSH scripts.
+ */
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
+
+/**
+ * Parse a standard scriptPubKey with one or more destination addresses. For
+ * multisig scripts, this populates the addressRet vector with the pubkey IDs
+ * and nRequiredRet with the n required to spend. For other destinations,
+ * addressRet is populated with a single value and nRequiredRet is set to 1.
+ * Returns true if successful. Currently does not extract address from
+ * pay-to-witness scripts.
+ */
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);
+/**
+ * Generate a Bitcoin scriptPubKey for the given CTxDestination. Returns a P2PKH
+ * script for a CKeyID destination, a P2SH script for a CScriptID, and an empty
+ * script for CNoDestination.
+ */
CScript GetScriptForDestination(const CTxDestination& dest);
+
+/** Generate a P2PK script for the given pubkey. */
CScript GetScriptForRawPubKey(const CPubKey& pubkey);
+
+/** Generate a multisig script. */
CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys);
+
+/**
+ * Generate a pay-to-witness script for the given redeem script. If the redeem
+ * script is P2PK or P2PKH, this returns a P2WPKH script, otherwise it returns a
+ * P2WSH script.
+ */
CScript GetScriptForWitness(const CScript& redeemscript);
#endif // BITCOIN_SCRIPT_STANDARD_H
diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am
index e5657f7f31..c071fbe275 100644
--- a/src/secp256k1/Makefile.am
+++ b/src/secp256k1/Makefile.am
@@ -93,7 +93,10 @@ TESTS =
if USE_TESTS
noinst_PROGRAMS += tests
tests_SOURCES = src/tests.c
-tests_CPPFLAGS = -DSECP256K1_BUILD -DVERIFY -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
+tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
+if !ENABLE_COVERAGE
+tests_CPPFLAGS += -DVERIFY
+endif
tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
tests_LDFLAGS = -static
TESTS += tests
@@ -102,7 +105,10 @@ endif
if USE_EXHAUSTIVE_TESTS
noinst_PROGRAMS += exhaustive_tests
exhaustive_tests_SOURCES = src/tests_exhaustive.c
-exhaustive_tests_CPPFLAGS = -DSECP256K1_BUILD -DVERIFY -I$(top_srcdir)/src $(SECP_INCLUDES)
+exhaustive_tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src $(SECP_INCLUDES)
+if !ENABLE_COVERAGE
+exhaustive_tests_CPPFLAGS += -DVERIFY
+endif
exhaustive_tests_LDADD = $(SECP_LIBS)
exhaustive_tests_LDFLAGS = -static
TESTS += exhaustive_tests
diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac
index ec50ffe3a2..e5fcbcb4ed 100644
--- a/src/secp256k1/configure.ac
+++ b/src/secp256k1/configure.ac
@@ -20,7 +20,7 @@ AC_PATH_TOOL(STRIP, strip)
AX_PROG_CC_FOR_BUILD
if test "x$CFLAGS" = "x"; then
- CFLAGS="-O3 -g"
+ CFLAGS="-g"
fi
AM_PROG_CC_C_O
@@ -89,6 +89,11 @@ AC_ARG_ENABLE(benchmark,
[use_benchmark=$enableval],
[use_benchmark=no])
+AC_ARG_ENABLE(coverage,
+ AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis]),
+ [enable_coverage=$enableval],
+ [enable_coverage=no])
+
AC_ARG_ENABLE(tests,
AS_HELP_STRING([--enable-tests],[compile tests (default is yes)]),
[use_tests=$enableval],
@@ -154,6 +159,14 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])],
[ AC_MSG_RESULT([no])
])
+if test x"$enable_coverage" = x"yes"; then
+ AC_DEFINE(COVERAGE, 1, [Define this symbol to compile out all VERIFY code])
+ CFLAGS="$CFLAGS -O0 --coverage"
+ LDFLAGS="--coverage"
+else
+ CFLAGS="$CFLAGS -O3"
+fi
+
if test x"$use_ecmult_static_precomputation" != x"no"; then
save_cross_compiling=$cross_compiling
cross_compiling=no
@@ -434,6 +447,7 @@ AC_MSG_NOTICE([Using field implementation: $set_field])
AC_MSG_NOTICE([Using bignum implementation: $set_bignum])
AC_MSG_NOTICE([Using scalar implementation: $set_scalar])
AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism])
+AC_MSG_NOTICE([Building for coverage analysis: $enable_coverage])
AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery])
AC_MSG_NOTICE([Using jni: $use_jni])
@@ -460,6 +474,7 @@ AC_SUBST(SECP_INCLUDES)
AC_SUBST(SECP_LIBS)
AC_SUBST(SECP_TEST_LIBS)
AC_SUBST(SECP_TEST_INCLUDES)
+AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"])
AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"])
AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$use_exhaustive_tests" != x"no"])
AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"])
diff --git a/src/secp256k1/contrib/lax_der_parsing.h b/src/secp256k1/contrib/lax_der_parsing.h
index 6d27871a7c..7eaf63bf6a 100644
--- a/src/secp256k1/contrib/lax_der_parsing.h
+++ b/src/secp256k1/contrib/lax_der_parsing.h
@@ -48,14 +48,14 @@
* 8.3.1.
*/
-#ifndef _SECP256K1_CONTRIB_LAX_DER_PARSING_H_
-#define _SECP256K1_CONTRIB_LAX_DER_PARSING_H_
+#ifndef SECP256K1_CONTRIB_LAX_DER_PARSING_H
+#define SECP256K1_CONTRIB_LAX_DER_PARSING_H
#include <secp256k1.h>
-# ifdef __cplusplus
+#ifdef __cplusplus
extern "C" {
-# endif
+#endif
/** Parse a signature in "lax DER" format
*
@@ -88,4 +88,4 @@ int ecdsa_signature_parse_der_lax(
}
#endif
-#endif
+#endif /* SECP256K1_CONTRIB_LAX_DER_PARSING_H */
diff --git a/src/secp256k1/contrib/lax_der_privatekey_parsing.h b/src/secp256k1/contrib/lax_der_privatekey_parsing.h
index 2fd088f8ab..fece261fb9 100644
--- a/src/secp256k1/contrib/lax_der_privatekey_parsing.h
+++ b/src/secp256k1/contrib/lax_der_privatekey_parsing.h
@@ -25,14 +25,14 @@
* library are sufficient.
*/
-#ifndef _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_
-#define _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_
+#ifndef SECP256K1_CONTRIB_BER_PRIVATEKEY_H
+#define SECP256K1_CONTRIB_BER_PRIVATEKEY_H
#include <secp256k1.h>
-# ifdef __cplusplus
+#ifdef __cplusplus
extern "C" {
-# endif
+#endif
/** Export a private key in DER format.
*
@@ -87,4 +87,4 @@ SECP256K1_WARN_UNUSED_RESULT int ec_privkey_import_der(
}
#endif
-#endif
+#endif /* SECP256K1_CONTRIB_BER_PRIVATEKEY_H */
diff --git a/src/secp256k1/include/secp256k1.h b/src/secp256k1/include/secp256k1.h
index f268e309d0..3e9c098d19 100644
--- a/src/secp256k1/include/secp256k1.h
+++ b/src/secp256k1/include/secp256k1.h
@@ -1,9 +1,9 @@
-#ifndef _SECP256K1_
-# define _SECP256K1_
+#ifndef SECP256K1_H
+#define SECP256K1_H
-# ifdef __cplusplus
+#ifdef __cplusplus
extern "C" {
-# endif
+#endif
#include <stddef.h>
@@ -61,7 +61,7 @@ typedef struct {
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
* If you need to convert to a format suitable for storage, transmission, or
* comparison, use the secp256k1_ecdsa_signature_serialize_* and
- * secp256k1_ecdsa_signature_serialize_* functions.
+ * secp256k1_ecdsa_signature_parse_* functions.
*/
typedef struct {
unsigned char data[64];
@@ -159,10 +159,19 @@ typedef int (*secp256k1_nonce_function)(
#define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION)
#define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION)
+/** Prefix byte used to tag various encoded curvepoints for specific purposes */
+#define SECP256K1_TAG_PUBKEY_EVEN 0x02
+#define SECP256K1_TAG_PUBKEY_ODD 0x03
+#define SECP256K1_TAG_PUBKEY_UNCOMPRESSED 0x04
+#define SECP256K1_TAG_PUBKEY_HYBRID_EVEN 0x06
+#define SECP256K1_TAG_PUBKEY_HYBRID_ODD 0x07
+
/** Create a secp256k1 context object.
*
* Returns: a newly created context object.
* In: flags: which parts of the context to initialize.
+ *
+ * See also secp256k1_context_randomize.
*/
SECP256K1_API secp256k1_context* secp256k1_context_create(
unsigned int flags
@@ -485,6 +494,28 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
const unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+/** Negates a private key in place.
+ *
+ * Returns: 1 always
+ * Args: ctx: pointer to a context object
+ * In/Out: pubkey: pointer to the public key to be negated (cannot be NULL)
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate(
+ const secp256k1_context* ctx,
+ unsigned char *seckey
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
+
+/** Negates a public key in place.
+ *
+ * Returns: 1 always
+ * Args: ctx: pointer to a context object
+ * In/Out: pubkey: pointer to the public key to be negated (cannot be NULL)
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate(
+ const secp256k1_context* ctx,
+ secp256k1_pubkey *pubkey
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
+
/** Tweak a private key by adding tweak to it.
* Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
* uniformly random 32-byte arrays, or if the resulting private key
@@ -543,11 +574,24 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
const unsigned char *tweak
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
-/** Updates the context randomization.
+/** Updates the context randomization to protect against side-channel leakage.
* Returns: 1: randomization successfully updated
* 0: error
* Args: ctx: pointer to a context object (cannot be NULL)
* In: seed32: pointer to a 32-byte random seed (NULL resets to initial state)
+ *
+ * While secp256k1 code is written to be constant-time no matter what secret
+ * values are, it's possible that a future compiler may output code which isn't,
+ * and also that the CPU may not emit the same radio frequencies or draw the same
+ * amount power for all values.
+ *
+ * This function provides a seed which is combined into the blinding value: that
+ * blinding value is added before each multiplication (and removed afterwards) so
+ * that it does not affect function results, but shields against attacks which
+ * rely on any input-dependent behaviour.
+ *
+ * You should call this after secp256k1_context_create or
+ * secp256k1_context_clone, and may call this repeatedly afterwards.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
secp256k1_context* ctx,
@@ -570,8 +614,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine(
size_t n
) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
-# ifdef __cplusplus
+#ifdef __cplusplus
}
-# endif
-
#endif
+
+#endif /* SECP256K1_H */
diff --git a/src/secp256k1/include/secp256k1_ecdh.h b/src/secp256k1/include/secp256k1_ecdh.h
index 4b84d7a963..88492dc1a4 100644
--- a/src/secp256k1/include/secp256k1_ecdh.h
+++ b/src/secp256k1/include/secp256k1_ecdh.h
@@ -1,11 +1,11 @@
-#ifndef _SECP256K1_ECDH_
-# define _SECP256K1_ECDH_
+#ifndef SECP256K1_ECDH_H
+#define SECP256K1_ECDH_H
-# include "secp256k1.h"
+#include "secp256k1.h"
-# ifdef __cplusplus
+#ifdef __cplusplus
extern "C" {
-# endif
+#endif
/** Compute an EC Diffie-Hellman secret in constant time
* Returns: 1: exponentiation was successful
@@ -24,8 +24,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh(
const unsigned char *privkey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
-# ifdef __cplusplus
+#ifdef __cplusplus
}
-# endif
-
#endif
+
+#endif /* SECP256K1_ECDH_H */
diff --git a/src/secp256k1/include/secp256k1_recovery.h b/src/secp256k1/include/secp256k1_recovery.h
index 0553797253..cf6c5ed7f5 100644
--- a/src/secp256k1/include/secp256k1_recovery.h
+++ b/src/secp256k1/include/secp256k1_recovery.h
@@ -1,11 +1,11 @@
-#ifndef _SECP256K1_RECOVERY_
-# define _SECP256K1_RECOVERY_
+#ifndef SECP256K1_RECOVERY_H
+#define SECP256K1_RECOVERY_H
-# include "secp256k1.h"
+#include "secp256k1.h"
-# ifdef __cplusplus
+#ifdef __cplusplus
extern "C" {
-# endif
+#endif
/** Opaque data structured that holds a parsed ECDSA signature,
* supporting pubkey recovery.
@@ -103,8 +103,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover(
const unsigned char *msg32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
-# ifdef __cplusplus
+#ifdef __cplusplus
}
-# endif
-
#endif
+
+#endif /* SECP256K1_RECOVERY_H */
diff --git a/src/secp256k1/sage/group_prover.sage b/src/secp256k1/sage/group_prover.sage
index ab580c5b23..8521f07999 100644
--- a/src/secp256k1/sage/group_prover.sage
+++ b/src/secp256k1/sage/group_prover.sage
@@ -3,7 +3,7 @@
# to independently set assumptions on input or intermediary variables.
#
# The general approach is:
-# * A constraint is a tuple of two sets of of symbolic expressions:
+# * A constraint is a tuple of two sets of symbolic expressions:
# the first of which are required to evaluate to zero, the second of which
# are required to evaluate to nonzero.
# - A constraint is said to be conflicting if any of its nonzero expressions
@@ -17,7 +17,7 @@
# - A constraint describing the requirements of the law, called "require"
# * Implementations are transliterated into functions that operate as well on
# algebraic input points, and are called once per combination of branches
-# exectured. Each execution returns:
+# executed. Each execution returns:
# - A constraint describing the assumptions this implementation requires
# (such as Z1=1), called "assumeFormula"
# - A constraint describing the assumptions this specific branch requires,
diff --git a/src/secp256k1/src/asm/field_10x26_arm.s b/src/secp256k1/src/asm/field_10x26_arm.s
index 5df561f2fc..5a9cc3ffcf 100644
--- a/src/secp256k1/src/asm/field_10x26_arm.s
+++ b/src/secp256k1/src/asm/field_10x26_arm.s
@@ -11,7 +11,7 @@ Note:
- To avoid unnecessary loads and make use of available registers, two
'passes' have every time been interleaved, with the odd passes accumulating c' and d'
- which will be added to c and d respectively in the the even passes
+ which will be added to c and d respectively in the even passes
*/
@@ -23,7 +23,7 @@ Note:
.eabi_attribute 10, 0 @ Tag_FP_arch = none
.eabi_attribute 24, 1 @ Tag_ABI_align_needed = 8-byte
.eabi_attribute 25, 1 @ Tag_ABI_align_preserved = 8-byte, except leaf SP
- .eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Agressive Speed
+ .eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Aggressive Speed
.eabi_attribute 34, 1 @ Tag_CPU_unaligned_access = v6
.text
diff --git a/src/secp256k1/src/basic-config.h b/src/secp256k1/src/basic-config.h
index c4c16eb7ca..fc588061ca 100644
--- a/src/secp256k1/src/basic-config.h
+++ b/src/secp256k1/src/basic-config.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_BASIC_CONFIG_
-#define _SECP256K1_BASIC_CONFIG_
+#ifndef SECP256K1_BASIC_CONFIG_H
+#define SECP256K1_BASIC_CONFIG_H
#ifdef USE_BASIC_CONFIG
@@ -28,5 +28,6 @@
#define USE_FIELD_10X26 1
#define USE_SCALAR_8X32 1
-#endif // USE_BASIC_CONFIG
-#endif // _SECP256K1_BASIC_CONFIG_
+#endif /* USE_BASIC_CONFIG */
+
+#endif /* SECP256K1_BASIC_CONFIG_H */
diff --git a/src/secp256k1/src/bench.h b/src/secp256k1/src/bench.h
index 3a71b4aafa..d5ebe01301 100644
--- a/src/secp256k1/src/bench.h
+++ b/src/secp256k1/src/bench.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_BENCH_H_
-#define _SECP256K1_BENCH_H_
+#ifndef SECP256K1_BENCH_H
+#define SECP256K1_BENCH_H
#include <stdio.h>
#include <math.h>
@@ -23,7 +23,7 @@ void print_number(double x) {
if (y < 0.0) {
y = -y;
}
- while (y < 100.0) {
+ while (y > 0 && y < 100.0) {
y *= 10.0;
c++;
}
@@ -63,4 +63,4 @@ void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), v
printf("us\n");
}
-#endif
+#endif /* SECP256K1_BENCH_H */
diff --git a/src/secp256k1/src/bench_schnorr_verify.c b/src/secp256k1/src/bench_schnorr_verify.c
deleted file mode 100644
index 5f137dda23..0000000000
--- a/src/secp256k1/src/bench_schnorr_verify.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/**********************************************************************
- * Copyright (c) 2014 Pieter Wuille *
- * Distributed under the MIT software license, see the accompanying *
- * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
- **********************************************************************/
-
-#include <stdio.h>
-#include <string.h>
-
-#include "include/secp256k1.h"
-#include "include/secp256k1_schnorr.h"
-#include "util.h"
-#include "bench.h"
-
-typedef struct {
- unsigned char key[32];
- unsigned char sig[64];
- unsigned char pubkey[33];
- size_t pubkeylen;
-} benchmark_schnorr_sig_t;
-
-typedef struct {
- secp256k1_context *ctx;
- unsigned char msg[32];
- benchmark_schnorr_sig_t sigs[64];
- int numsigs;
-} benchmark_schnorr_verify_t;
-
-static void benchmark_schnorr_init(void* arg) {
- int i, k;
- benchmark_schnorr_verify_t* data = (benchmark_schnorr_verify_t*)arg;
-
- for (i = 0; i < 32; i++) {
- data->msg[i] = 1 + i;
- }
- for (k = 0; k < data->numsigs; k++) {
- secp256k1_pubkey pubkey;
- for (i = 0; i < 32; i++) {
- data->sigs[k].key[i] = 33 + i + k;
- }
- secp256k1_schnorr_sign(data->ctx, data->sigs[k].sig, data->msg, data->sigs[k].key, NULL, NULL);
- data->sigs[k].pubkeylen = 33;
- CHECK(secp256k1_ec_pubkey_create(data->ctx, &pubkey, data->sigs[k].key));
- CHECK(secp256k1_ec_pubkey_serialize(data->ctx, data->sigs[k].pubkey, &data->sigs[k].pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED));
- }
-}
-
-static void benchmark_schnorr_verify(void* arg) {
- int i;
- benchmark_schnorr_verify_t* data = (benchmark_schnorr_verify_t*)arg;
-
- for (i = 0; i < 20000 / data->numsigs; i++) {
- secp256k1_pubkey pubkey;
- data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF);
- CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->sigs[0].pubkey, data->sigs[0].pubkeylen));
- CHECK(secp256k1_schnorr_verify(data->ctx, data->sigs[0].sig, data->msg, &pubkey) == ((i & 0xFF) == 0));
- data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF);
- }
-}
-
-
-
-int main(void) {
- benchmark_schnorr_verify_t data;
-
- data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
-
- data.numsigs = 1;
- run_benchmark("schnorr_verify", benchmark_schnorr_verify, benchmark_schnorr_init, NULL, &data, 10, 20000);
-
- secp256k1_context_destroy(data.ctx);
- return 0;
-}
diff --git a/src/secp256k1/src/ecdsa.h b/src/secp256k1/src/ecdsa.h
index 54ae101b92..80590c7cc8 100644
--- a/src/secp256k1/src/ecdsa.h
+++ b/src/secp256k1/src/ecdsa.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_ECDSA_
-#define _SECP256K1_ECDSA_
+#ifndef SECP256K1_ECDSA_H
+#define SECP256K1_ECDSA_H
#include <stddef.h>
@@ -18,4 +18,4 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const
static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar* r, const secp256k1_scalar* s, const secp256k1_ge *pubkey, const secp256k1_scalar *message);
static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid);
-#endif
+#endif /* SECP256K1_ECDSA_H */
diff --git a/src/secp256k1/src/ecdsa_impl.h b/src/secp256k1/src/ecdsa_impl.h
index 9a42e519bd..c3400042d8 100644
--- a/src/secp256k1/src/ecdsa_impl.h
+++ b/src/secp256k1/src/ecdsa_impl.h
@@ -5,8 +5,8 @@
**********************************************************************/
-#ifndef _SECP256K1_ECDSA_IMPL_H_
-#define _SECP256K1_ECDSA_IMPL_H_
+#ifndef SECP256K1_ECDSA_IMPL_H
+#define SECP256K1_ECDSA_IMPL_H
#include "scalar.h"
#include "field.h"
@@ -81,8 +81,6 @@ static int secp256k1_der_read_len(const unsigned char **sigp, const unsigned cha
return -1;
}
while (lenleft > 0) {
- if ((ret >> ((sizeof(size_t) - 1) * 8)) != 0) {
- }
ret = (ret << 8) | **sigp;
if (ret + lenleft > (size_t)(sigend - *sigp)) {
/* Result exceeds the length of the passed array. */
@@ -225,14 +223,12 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const
#if defined(EXHAUSTIVE_TEST_ORDER)
{
secp256k1_scalar computed_r;
- int overflow = 0;
secp256k1_ge pr_ge;
secp256k1_ge_set_gej(&pr_ge, &pr);
secp256k1_fe_normalize(&pr_ge.x);
secp256k1_fe_get_b32(c, &pr_ge.x);
- secp256k1_scalar_set_b32(&computed_r, c, &overflow);
- /* we fully expect overflow */
+ secp256k1_scalar_set_b32(&computed_r, c, NULL);
return secp256k1_scalar_eq(sigr, &computed_r);
}
#else
@@ -285,14 +281,10 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, sec
secp256k1_fe_normalize(&r.y);
secp256k1_fe_get_b32(b, &r.x);
secp256k1_scalar_set_b32(sigr, b, &overflow);
- if (secp256k1_scalar_is_zero(sigr)) {
- /* P.x = order is on the curve, so technically sig->r could end up zero, which would be an invalid signature.
- * This branch is cryptographically unreachable as hitting it requires finding the discrete log of P.x = N.
- */
- secp256k1_gej_clear(&rp);
- secp256k1_ge_clear(&r);
- return 0;
- }
+ /* These two conditions should be checked before calling */
+ VERIFY_CHECK(!secp256k1_scalar_is_zero(sigr));
+ VERIFY_CHECK(overflow == 0);
+
if (recid) {
/* The overflow condition is cryptographically unreachable as hitting it requires finding the discrete log
* of some P where P.x >= order, and only 1 in about 2^127 points meet this criteria.
@@ -318,4 +310,4 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, sec
return 1;
}
-#endif
+#endif /* SECP256K1_ECDSA_IMPL_H */
diff --git a/src/secp256k1/src/eckey.h b/src/secp256k1/src/eckey.h
index 42739a3bea..b621f1e6c3 100644
--- a/src/secp256k1/src/eckey.h
+++ b/src/secp256k1/src/eckey.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_ECKEY_
-#define _SECP256K1_ECKEY_
+#ifndef SECP256K1_ECKEY_H
+#define SECP256K1_ECKEY_H
#include <stddef.h>
@@ -22,4 +22,4 @@ static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx,
static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak);
static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak);
-#endif
+#endif /* SECP256K1_ECKEY_H */
diff --git a/src/secp256k1/src/eckey_impl.h b/src/secp256k1/src/eckey_impl.h
index ce38071ac2..1ab9a68ec0 100644
--- a/src/secp256k1/src/eckey_impl.h
+++ b/src/secp256k1/src/eckey_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_ECKEY_IMPL_H_
-#define _SECP256K1_ECKEY_IMPL_H_
+#ifndef SECP256K1_ECKEY_IMPL_H
+#define SECP256K1_ECKEY_IMPL_H
#include "eckey.h"
@@ -15,16 +15,17 @@
#include "ecmult_gen.h"
static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) {
- if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) {
+ if (size == 33 && (pub[0] == SECP256K1_TAG_PUBKEY_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_ODD)) {
secp256k1_fe x;
- return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == 0x03);
+ return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD);
} else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) {
secp256k1_fe x, y;
if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) {
return 0;
}
secp256k1_ge_set_xy(elem, &x, &y);
- if ((pub[0] == 0x06 || pub[0] == 0x07) && secp256k1_fe_is_odd(&y) != (pub[0] == 0x07)) {
+ if ((pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD) &&
+ secp256k1_fe_is_odd(&y) != (pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) {
return 0;
}
return secp256k1_ge_is_valid_var(elem);
@@ -42,10 +43,10 @@ static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *p
secp256k1_fe_get_b32(&pub[1], &elem->x);
if (compressed) {
*size = 33;
- pub[0] = 0x02 | (secp256k1_fe_is_odd(&elem->y) ? 0x01 : 0x00);
+ pub[0] = secp256k1_fe_is_odd(&elem->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN;
} else {
*size = 65;
- pub[0] = 0x04;
+ pub[0] = SECP256K1_TAG_PUBKEY_UNCOMPRESSED;
secp256k1_fe_get_b32(&pub[33], &elem->y);
}
return 1;
@@ -96,4 +97,4 @@ static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx,
return 1;
}
-#endif
+#endif /* SECP256K1_ECKEY_IMPL_H */
diff --git a/src/secp256k1/src/ecmult.h b/src/secp256k1/src/ecmult.h
index 20484134f5..6d44aba60b 100644
--- a/src/secp256k1/src/ecmult.h
+++ b/src/secp256k1/src/ecmult.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_ECMULT_
-#define _SECP256K1_ECMULT_
+#ifndef SECP256K1_ECMULT_H
+#define SECP256K1_ECMULT_H
#include "num.h"
#include "group.h"
@@ -28,4 +28,4 @@ static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx
/** Double multiply: R = na*A + ng*G */
static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng);
-#endif
+#endif /* SECP256K1_ECMULT_H */
diff --git a/src/secp256k1/src/ecmult_const.h b/src/secp256k1/src/ecmult_const.h
index 2b0097655c..72bf7d7582 100644
--- a/src/secp256k1/src/ecmult_const.h
+++ b/src/secp256k1/src/ecmult_const.h
@@ -4,12 +4,12 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_ECMULT_CONST_
-#define _SECP256K1_ECMULT_CONST_
+#ifndef SECP256K1_ECMULT_CONST_H
+#define SECP256K1_ECMULT_CONST_H
#include "scalar.h"
#include "group.h"
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q);
-#endif
+#endif /* SECP256K1_ECMULT_CONST_H */
diff --git a/src/secp256k1/src/ecmult_const_impl.h b/src/secp256k1/src/ecmult_const_impl.h
index 0db314c48e..7d7a172b7b 100644
--- a/src/secp256k1/src/ecmult_const_impl.h
+++ b/src/secp256k1/src/ecmult_const_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_ECMULT_CONST_IMPL_
-#define _SECP256K1_ECMULT_CONST_IMPL_
+#ifndef SECP256K1_ECMULT_CONST_IMPL_H
+#define SECP256K1_ECMULT_CONST_IMPL_H
#include "scalar.h"
#include "group.h"
@@ -42,11 +42,12 @@
} while(0)
-/** Convert a number to WNAF notation. The number becomes represented by sum(2^{wi} * wnaf[i], i=0..return_val)
- * with the following guarantees:
+/** Convert a number to WNAF notation.
+ * The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val.
+ * It has the following guarantees:
* - each wnaf[i] an odd integer between -(1 << w) and (1 << w)
* - each wnaf[i] is nonzero
- * - the number of words set is returned; this is always (WNAF_BITS + w - 1) / w
+ * - the number of words set is always WNAF_SIZE(w) + 1
*
* Adapted from `The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar
* Multiplications Secure against Side Channel Attacks`, Okeya and Tagaki. M. Joye (Ed.)
@@ -236,4 +237,4 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
}
}
-#endif
+#endif /* SECP256K1_ECMULT_CONST_IMPL_H */
diff --git a/src/secp256k1/src/ecmult_gen.h b/src/secp256k1/src/ecmult_gen.h
index eb2cc9ead6..7564b7015f 100644
--- a/src/secp256k1/src/ecmult_gen.h
+++ b/src/secp256k1/src/ecmult_gen.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_ECMULT_GEN_
-#define _SECP256K1_ECMULT_GEN_
+#ifndef SECP256K1_ECMULT_GEN_H
+#define SECP256K1_ECMULT_GEN_H
#include "scalar.h"
#include "group.h"
@@ -40,4 +40,4 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context* ctx, secp25
static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32);
-#endif
+#endif /* SECP256K1_ECMULT_GEN_H */
diff --git a/src/secp256k1/src/ecmult_gen_impl.h b/src/secp256k1/src/ecmult_gen_impl.h
index 35f2546077..9615b932dd 100644
--- a/src/secp256k1/src/ecmult_gen_impl.h
+++ b/src/secp256k1/src/ecmult_gen_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_ECMULT_GEN_IMPL_H_
-#define _SECP256K1_ECMULT_GEN_IMPL_H_
+#ifndef SECP256K1_ECMULT_GEN_IMPL_H
+#define SECP256K1_ECMULT_GEN_IMPL_H
#include "scalar.h"
#include "group.h"
@@ -207,4 +207,4 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
secp256k1_gej_clear(&gb);
}
-#endif
+#endif /* SECP256K1_ECMULT_GEN_IMPL_H */
diff --git a/src/secp256k1/src/ecmult_impl.h b/src/secp256k1/src/ecmult_impl.h
index 4e40104ad4..93d3794cb4 100644
--- a/src/secp256k1/src/ecmult_impl.h
+++ b/src/secp256k1/src/ecmult_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_ECMULT_IMPL_H_
-#define _SECP256K1_ECMULT_IMPL_H_
+#ifndef SECP256K1_ECMULT_IMPL_H
+#define SECP256K1_ECMULT_IMPL_H
#include <string.h>
@@ -403,4 +403,4 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej
}
}
-#endif
+#endif /* SECP256K1_ECMULT_IMPL_H */
diff --git a/src/secp256k1/src/field.h b/src/secp256k1/src/field.h
index bbb1ee866c..bb6692ad57 100644
--- a/src/secp256k1/src/field.h
+++ b/src/secp256k1/src/field.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_FIELD_
-#define _SECP256K1_FIELD_
+#ifndef SECP256K1_FIELD_H
+#define SECP256K1_FIELD_H
/** Field element module.
*
@@ -129,4 +129,4 @@ static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_f
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
-#endif
+#endif /* SECP256K1_FIELD_H */
diff --git a/src/secp256k1/src/field_10x26.h b/src/secp256k1/src/field_10x26.h
index 61ee1e0965..727c5267fb 100644
--- a/src/secp256k1/src/field_10x26.h
+++ b/src/secp256k1/src/field_10x26.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_FIELD_REPR_
-#define _SECP256K1_FIELD_REPR_
+#ifndef SECP256K1_FIELD_REPR_H
+#define SECP256K1_FIELD_REPR_H
#include <stdint.h>
@@ -44,4 +44,5 @@ typedef struct {
#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }}
#define SECP256K1_FE_STORAGE_CONST_GET(d) d.n[7], d.n[6], d.n[5], d.n[4],d.n[3], d.n[2], d.n[1], d.n[0]
-#endif
+
+#endif /* SECP256K1_FIELD_REPR_H */
diff --git a/src/secp256k1/src/field_10x26_impl.h b/src/secp256k1/src/field_10x26_impl.h
index 7b8c079608..94f8132fc8 100644
--- a/src/secp256k1/src/field_10x26_impl.h
+++ b/src/secp256k1/src/field_10x26_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
-#define _SECP256K1_FIELD_REPR_IMPL_H_
+#ifndef SECP256K1_FIELD_REPR_IMPL_H
+#define SECP256K1_FIELD_REPR_IMPL_H
#include "util.h"
#include "num.h"
@@ -38,10 +38,6 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) {
}
VERIFY_CHECK(r == 1);
}
-#else
-static void secp256k1_fe_verify(const secp256k1_fe *a) {
- (void)a;
-}
#endif
static void secp256k1_fe_normalize(secp256k1_fe *r) {
@@ -325,17 +321,17 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
}
static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
- int i;
- r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
- r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0;
- for (i=0; i<32; i++) {
- int j;
- for (j=0; j<4; j++) {
- int limb = (8*i+2*j)/26;
- int shift = (8*i+2*j)%26;
- r->n[limb] |= (uint32_t)((a[31-i] >> (2*j)) & 0x3) << shift;
- }
- }
+ r->n[0] = (uint32_t)a[31] | ((uint32_t)a[30] << 8) | ((uint32_t)a[29] << 16) | ((uint32_t)(a[28] & 0x3) << 24);
+ r->n[1] = (uint32_t)((a[28] >> 2) & 0x3f) | ((uint32_t)a[27] << 6) | ((uint32_t)a[26] << 14) | ((uint32_t)(a[25] & 0xf) << 22);
+ r->n[2] = (uint32_t)((a[25] >> 4) & 0xf) | ((uint32_t)a[24] << 4) | ((uint32_t)a[23] << 12) | ((uint32_t)(a[22] & 0x3f) << 20);
+ r->n[3] = (uint32_t)((a[22] >> 6) & 0x3) | ((uint32_t)a[21] << 2) | ((uint32_t)a[20] << 10) | ((uint32_t)a[19] << 18);
+ r->n[4] = (uint32_t)a[18] | ((uint32_t)a[17] << 8) | ((uint32_t)a[16] << 16) | ((uint32_t)(a[15] & 0x3) << 24);
+ r->n[5] = (uint32_t)((a[15] >> 2) & 0x3f) | ((uint32_t)a[14] << 6) | ((uint32_t)a[13] << 14) | ((uint32_t)(a[12] & 0xf) << 22);
+ r->n[6] = (uint32_t)((a[12] >> 4) & 0xf) | ((uint32_t)a[11] << 4) | ((uint32_t)a[10] << 12) | ((uint32_t)(a[9] & 0x3f) << 20);
+ r->n[7] = (uint32_t)((a[9] >> 6) & 0x3) | ((uint32_t)a[8] << 2) | ((uint32_t)a[7] << 10) | ((uint32_t)a[6] << 18);
+ r->n[8] = (uint32_t)a[5] | ((uint32_t)a[4] << 8) | ((uint32_t)a[3] << 16) | ((uint32_t)(a[2] & 0x3) << 24);
+ r->n[9] = (uint32_t)((a[2] >> 2) & 0x3f) | ((uint32_t)a[1] << 6) | ((uint32_t)a[0] << 14);
+
if (r->n[9] == 0x3FFFFFUL && (r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL && (r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL) {
return 0;
}
@@ -349,21 +345,42 @@ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
- int i;
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
secp256k1_fe_verify(a);
#endif
- for (i=0; i<32; i++) {
- int j;
- int c = 0;
- for (j=0; j<4; j++) {
- int limb = (8*i+2*j)/26;
- int shift = (8*i+2*j)%26;
- c |= ((a->n[limb] >> shift) & 0x3) << (2 * j);
- }
- r[31-i] = c;
- }
+ r[0] = (a->n[9] >> 14) & 0xff;
+ r[1] = (a->n[9] >> 6) & 0xff;
+ r[2] = ((a->n[9] & 0x3F) << 2) | ((a->n[8] >> 24) & 0x3);
+ r[3] = (a->n[8] >> 16) & 0xff;
+ r[4] = (a->n[8] >> 8) & 0xff;
+ r[5] = a->n[8] & 0xff;
+ r[6] = (a->n[7] >> 18) & 0xff;
+ r[7] = (a->n[7] >> 10) & 0xff;
+ r[8] = (a->n[7] >> 2) & 0xff;
+ r[9] = ((a->n[7] & 0x3) << 6) | ((a->n[6] >> 20) & 0x3f);
+ r[10] = (a->n[6] >> 12) & 0xff;
+ r[11] = (a->n[6] >> 4) & 0xff;
+ r[12] = ((a->n[6] & 0xf) << 4) | ((a->n[5] >> 22) & 0xf);
+ r[13] = (a->n[5] >> 14) & 0xff;
+ r[14] = (a->n[5] >> 6) & 0xff;
+ r[15] = ((a->n[5] & 0x3f) << 2) | ((a->n[4] >> 24) & 0x3);
+ r[16] = (a->n[4] >> 16) & 0xff;
+ r[17] = (a->n[4] >> 8) & 0xff;
+ r[18] = a->n[4] & 0xff;
+ r[19] = (a->n[3] >> 18) & 0xff;
+ r[20] = (a->n[3] >> 10) & 0xff;
+ r[21] = (a->n[3] >> 2) & 0xff;
+ r[22] = ((a->n[3] & 0x3) << 6) | ((a->n[2] >> 20) & 0x3f);
+ r[23] = (a->n[2] >> 12) & 0xff;
+ r[24] = (a->n[2] >> 4) & 0xff;
+ r[25] = ((a->n[2] & 0xf) << 4) | ((a->n[1] >> 22) & 0xf);
+ r[26] = (a->n[1] >> 14) & 0xff;
+ r[27] = (a->n[1] >> 6) & 0xff;
+ r[28] = ((a->n[1] & 0x3f) << 2) | ((a->n[0] >> 24) & 0x3);
+ r[29] = (a->n[0] >> 16) & 0xff;
+ r[30] = (a->n[0] >> 8) & 0xff;
+ r[31] = a->n[0] & 0xff;
}
SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
@@ -1141,4 +1158,4 @@ static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const se
#endif
}
-#endif
+#endif /* SECP256K1_FIELD_REPR_IMPL_H */
diff --git a/src/secp256k1/src/field_5x52.h b/src/secp256k1/src/field_5x52.h
index 8e69a560dc..bccd8feb4d 100644
--- a/src/secp256k1/src/field_5x52.h
+++ b/src/secp256k1/src/field_5x52.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_FIELD_REPR_
-#define _SECP256K1_FIELD_REPR_
+#ifndef SECP256K1_FIELD_REPR_H
+#define SECP256K1_FIELD_REPR_H
#include <stdint.h>
@@ -44,4 +44,4 @@ typedef struct {
(d6) | (((uint64_t)(d7)) << 32) \
}}
-#endif
+#endif /* SECP256K1_FIELD_REPR_H */
diff --git a/src/secp256k1/src/field_5x52_asm_impl.h b/src/secp256k1/src/field_5x52_asm_impl.h
index 98cc004bf0..1fc3171f6b 100644
--- a/src/secp256k1/src/field_5x52_asm_impl.h
+++ b/src/secp256k1/src/field_5x52_asm_impl.h
@@ -11,8 +11,8 @@
* - December 2014, Pieter Wuille: converted from YASM to GCC inline assembly
*/
-#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_
-#define _SECP256K1_FIELD_INNER5X52_IMPL_H_
+#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H
+#define SECP256K1_FIELD_INNER5X52_IMPL_H
SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) {
/**
@@ -499,4 +499,4 @@ __asm__ __volatile__(
);
}
-#endif
+#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */
diff --git a/src/secp256k1/src/field_5x52_impl.h b/src/secp256k1/src/field_5x52_impl.h
index 7a99eb21ec..957c61b014 100644
--- a/src/secp256k1/src/field_5x52_impl.h
+++ b/src/secp256k1/src/field_5x52_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
-#define _SECP256K1_FIELD_REPR_IMPL_H_
+#ifndef SECP256K1_FIELD_REPR_IMPL_H
+#define SECP256K1_FIELD_REPR_IMPL_H
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
@@ -49,10 +49,6 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) {
}
VERIFY_CHECK(r == 1);
}
-#else
-static void secp256k1_fe_verify(const secp256k1_fe *a) {
- (void)a;
-}
#endif
static void secp256k1_fe_normalize(secp256k1_fe *r) {
@@ -288,16 +284,40 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
}
static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
- int i;
- r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
- for (i=0; i<32; i++) {
- int j;
- for (j=0; j<2; j++) {
- int limb = (8*i+4*j)/52;
- int shift = (8*i+4*j)%52;
- r->n[limb] |= (uint64_t)((a[31-i] >> (4*j)) & 0xF) << shift;
- }
- }
+ r->n[0] = (uint64_t)a[31]
+ | ((uint64_t)a[30] << 8)
+ | ((uint64_t)a[29] << 16)
+ | ((uint64_t)a[28] << 24)
+ | ((uint64_t)a[27] << 32)
+ | ((uint64_t)a[26] << 40)
+ | ((uint64_t)(a[25] & 0xF) << 48);
+ r->n[1] = (uint64_t)((a[25] >> 4) & 0xF)
+ | ((uint64_t)a[24] << 4)
+ | ((uint64_t)a[23] << 12)
+ | ((uint64_t)a[22] << 20)
+ | ((uint64_t)a[21] << 28)
+ | ((uint64_t)a[20] << 36)
+ | ((uint64_t)a[19] << 44);
+ r->n[2] = (uint64_t)a[18]
+ | ((uint64_t)a[17] << 8)
+ | ((uint64_t)a[16] << 16)
+ | ((uint64_t)a[15] << 24)
+ | ((uint64_t)a[14] << 32)
+ | ((uint64_t)a[13] << 40)
+ | ((uint64_t)(a[12] & 0xF) << 48);
+ r->n[3] = (uint64_t)((a[12] >> 4) & 0xF)
+ | ((uint64_t)a[11] << 4)
+ | ((uint64_t)a[10] << 12)
+ | ((uint64_t)a[9] << 20)
+ | ((uint64_t)a[8] << 28)
+ | ((uint64_t)a[7] << 36)
+ | ((uint64_t)a[6] << 44);
+ r->n[4] = (uint64_t)a[5]
+ | ((uint64_t)a[4] << 8)
+ | ((uint64_t)a[3] << 16)
+ | ((uint64_t)a[2] << 24)
+ | ((uint64_t)a[1] << 32)
+ | ((uint64_t)a[0] << 40);
if (r->n[4] == 0x0FFFFFFFFFFFFULL && (r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL && r->n[0] >= 0xFFFFEFFFFFC2FULL) {
return 0;
}
@@ -311,21 +331,42 @@ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
- int i;
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
secp256k1_fe_verify(a);
#endif
- for (i=0; i<32; i++) {
- int j;
- int c = 0;
- for (j=0; j<2; j++) {
- int limb = (8*i+4*j)/52;
- int shift = (8*i+4*j)%52;
- c |= ((a->n[limb] >> shift) & 0xF) << (4 * j);
- }
- r[31-i] = c;
- }
+ r[0] = (a->n[4] >> 40) & 0xFF;
+ r[1] = (a->n[4] >> 32) & 0xFF;
+ r[2] = (a->n[4] >> 24) & 0xFF;
+ r[3] = (a->n[4] >> 16) & 0xFF;
+ r[4] = (a->n[4] >> 8) & 0xFF;
+ r[5] = a->n[4] & 0xFF;
+ r[6] = (a->n[3] >> 44) & 0xFF;
+ r[7] = (a->n[3] >> 36) & 0xFF;
+ r[8] = (a->n[3] >> 28) & 0xFF;
+ r[9] = (a->n[3] >> 20) & 0xFF;
+ r[10] = (a->n[3] >> 12) & 0xFF;
+ r[11] = (a->n[3] >> 4) & 0xFF;
+ r[12] = ((a->n[2] >> 48) & 0xF) | ((a->n[3] & 0xF) << 4);
+ r[13] = (a->n[2] >> 40) & 0xFF;
+ r[14] = (a->n[2] >> 32) & 0xFF;
+ r[15] = (a->n[2] >> 24) & 0xFF;
+ r[16] = (a->n[2] >> 16) & 0xFF;
+ r[17] = (a->n[2] >> 8) & 0xFF;
+ r[18] = a->n[2] & 0xFF;
+ r[19] = (a->n[1] >> 44) & 0xFF;
+ r[20] = (a->n[1] >> 36) & 0xFF;
+ r[21] = (a->n[1] >> 28) & 0xFF;
+ r[22] = (a->n[1] >> 20) & 0xFF;
+ r[23] = (a->n[1] >> 12) & 0xFF;
+ r[24] = (a->n[1] >> 4) & 0xFF;
+ r[25] = ((a->n[0] >> 48) & 0xF) | ((a->n[1] & 0xF) << 4);
+ r[26] = (a->n[0] >> 40) & 0xFF;
+ r[27] = (a->n[0] >> 32) & 0xFF;
+ r[28] = (a->n[0] >> 24) & 0xFF;
+ r[29] = (a->n[0] >> 16) & 0xFF;
+ r[30] = (a->n[0] >> 8) & 0xFF;
+ r[31] = a->n[0] & 0xFF;
}
SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
@@ -452,4 +493,4 @@ static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const se
#endif
}
-#endif
+#endif /* SECP256K1_FIELD_REPR_IMPL_H */
diff --git a/src/secp256k1/src/field_5x52_int128_impl.h b/src/secp256k1/src/field_5x52_int128_impl.h
index 0bf22bdd3e..95a0d1791c 100644
--- a/src/secp256k1/src/field_5x52_int128_impl.h
+++ b/src/secp256k1/src/field_5x52_int128_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_
-#define _SECP256K1_FIELD_INNER5X52_IMPL_H_
+#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H
+#define SECP256K1_FIELD_INNER5X52_IMPL_H
#include <stdint.h>
@@ -274,4 +274,4 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t
/* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
}
-#endif
+#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */
diff --git a/src/secp256k1/src/field_impl.h b/src/secp256k1/src/field_impl.h
index 5127b279bc..20428648af 100644
--- a/src/secp256k1/src/field_impl.h
+++ b/src/secp256k1/src/field_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_FIELD_IMPL_H_
-#define _SECP256K1_FIELD_IMPL_H_
+#ifndef SECP256K1_FIELD_IMPL_H
+#define SECP256K1_FIELD_IMPL_H
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
@@ -312,4 +312,4 @@ static int secp256k1_fe_is_quad_var(const secp256k1_fe *a) {
#endif
}
-#endif
+#endif /* SECP256K1_FIELD_IMPL_H */
diff --git a/src/secp256k1/src/group.h b/src/secp256k1/src/group.h
index 4957b248fe..ea1302deb8 100644
--- a/src/secp256k1/src/group.h
+++ b/src/secp256k1/src/group.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_GROUP_
-#define _SECP256K1_GROUP_
+#ifndef SECP256K1_GROUP_H
+#define SECP256K1_GROUP_H
#include "num.h"
#include "field.h"
@@ -141,4 +141,4 @@ static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_g
/** Rescale a jacobian point by b which must be non-zero. Constant-time. */
static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b);
-#endif
+#endif /* SECP256K1_GROUP_H */
diff --git a/src/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h
index 2e192b62fd..b31b6c12ef 100644
--- a/src/secp256k1/src/group_impl.h
+++ b/src/secp256k1/src/group_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_GROUP_IMPL_H_
-#define _SECP256K1_GROUP_IMPL_H_
+#ifndef SECP256K1_GROUP_IMPL_H
+#define SECP256K1_GROUP_IMPL_H
#include "num.h"
#include "field.h"
@@ -200,12 +200,6 @@ static void secp256k1_gej_set_infinity(secp256k1_gej *r) {
secp256k1_fe_clear(&r->z);
}
-static void secp256k1_ge_set_infinity(secp256k1_ge *r) {
- r->infinity = 1;
- secp256k1_fe_clear(&r->x);
- secp256k1_fe_clear(&r->y);
-}
-
static void secp256k1_gej_clear(secp256k1_gej *r) {
r->infinity = 0;
secp256k1_fe_clear(&r->x);
@@ -703,4 +697,4 @@ static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) {
return secp256k1_fe_is_quad_var(&yz);
}
-#endif
+#endif /* SECP256K1_GROUP_IMPL_H */
diff --git a/src/secp256k1/src/hash.h b/src/secp256k1/src/hash.h
index fca98cab9f..e08d25d225 100644
--- a/src/secp256k1/src/hash.h
+++ b/src/secp256k1/src/hash.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_HASH_
-#define _SECP256K1_HASH_
+#ifndef SECP256K1_HASH_H
+#define SECP256K1_HASH_H
#include <stdlib.h>
#include <stdint.h>
@@ -38,4 +38,4 @@ static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha2
static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen);
static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng);
-#endif
+#endif /* SECP256K1_HASH_H */
diff --git a/src/secp256k1/src/hash_impl.h b/src/secp256k1/src/hash_impl.h
index b47e65f830..4c9964ee06 100644
--- a/src/secp256k1/src/hash_impl.h
+++ b/src/secp256k1/src/hash_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_HASH_IMPL_H_
-#define _SECP256K1_HASH_IMPL_H_
+#ifndef SECP256K1_HASH_IMPL_H
+#define SECP256K1_HASH_IMPL_H
#include "hash.h"
@@ -278,4 +278,4 @@ static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256
#undef Maj
#undef Ch
-#endif
+#endif /* SECP256K1_HASH_IMPL_H */
diff --git a/src/secp256k1/src/modules/ecdh/main_impl.h b/src/secp256k1/src/modules/ecdh/main_impl.h
index c23e4f82f7..01ecba4d53 100644
--- a/src/secp256k1/src/modules/ecdh/main_impl.h
+++ b/src/secp256k1/src/modules/ecdh/main_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_MODULE_ECDH_MAIN_
-#define _SECP256K1_MODULE_ECDH_MAIN_
+#ifndef SECP256K1_MODULE_ECDH_MAIN_H
+#define SECP256K1_MODULE_ECDH_MAIN_H
#include "include/secp256k1_ecdh.h"
#include "ecmult_const_impl.h"
@@ -16,10 +16,10 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const se
secp256k1_gej res;
secp256k1_ge pt;
secp256k1_scalar s;
+ VERIFY_CHECK(ctx != NULL);
ARG_CHECK(result != NULL);
ARG_CHECK(point != NULL);
ARG_CHECK(scalar != NULL);
- (void)ctx;
secp256k1_pubkey_load(ctx, &pt, point);
secp256k1_scalar_set_b32(&s, scalar, &overflow);
@@ -51,4 +51,4 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const se
return ret;
}
-#endif
+#endif /* SECP256K1_MODULE_ECDH_MAIN_H */
diff --git a/src/secp256k1/src/modules/ecdh/tests_impl.h b/src/secp256k1/src/modules/ecdh/tests_impl.h
index 7badc9033f..cec30b67c6 100644
--- a/src/secp256k1/src/modules/ecdh/tests_impl.h
+++ b/src/secp256k1/src/modules/ecdh/tests_impl.h
@@ -4,8 +4,37 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_MODULE_ECDH_TESTS_
-#define _SECP256K1_MODULE_ECDH_TESTS_
+#ifndef SECP256K1_MODULE_ECDH_TESTS_H
+#define SECP256K1_MODULE_ECDH_TESTS_H
+
+void test_ecdh_api(void) {
+ /* Setup context that just counts errors */
+ secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
+ secp256k1_pubkey point;
+ unsigned char res[32];
+ unsigned char s_one[32] = { 0 };
+ int32_t ecount = 0;
+ s_one[31] = 1;
+
+ secp256k1_context_set_error_callback(tctx, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(tctx, counting_illegal_callback_fn, &ecount);
+ CHECK(secp256k1_ec_pubkey_create(tctx, &point, s_one) == 1);
+
+ /* Check all NULLs are detected */
+ CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1);
+ CHECK(ecount == 0);
+ CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_ecdh(tctx, res, NULL, s_one) == 0);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ecdh(tctx, res, &point, NULL) == 0);
+ CHECK(ecount == 3);
+ CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1);
+ CHECK(ecount == 3);
+
+ /* Cleanup */
+ secp256k1_context_destroy(tctx);
+}
void test_ecdh_generator_basepoint(void) {
unsigned char s_one[32] = { 0 };
@@ -68,8 +97,9 @@ void test_bad_scalar(void) {
}
void run_ecdh_tests(void) {
+ test_ecdh_api();
test_ecdh_generator_basepoint();
test_bad_scalar();
}
-#endif
+#endif /* SECP256K1_MODULE_ECDH_TESTS_H */
diff --git a/src/secp256k1/src/modules/recovery/main_impl.h b/src/secp256k1/src/modules/recovery/main_impl.h
index 86f2f0cb2b..2f6691c5a1 100755
--- a/src/secp256k1/src/modules/recovery/main_impl.h
+++ b/src/secp256k1/src/modules/recovery/main_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_MODULE_RECOVERY_MAIN_
-#define _SECP256K1_MODULE_RECOVERY_MAIN_
+#ifndef SECP256K1_MODULE_RECOVERY_MAIN_H
+#define SECP256K1_MODULE_RECOVERY_MAIN_H
#include "include/secp256k1_recovery.h"
@@ -179,7 +179,7 @@ int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubk
ARG_CHECK(pubkey != NULL);
secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, signature);
- ARG_CHECK(recid >= 0 && recid < 4);
+ VERIFY_CHECK(recid >= 0 && recid < 4); /* should have been caught in parse_compact */
secp256k1_scalar_set_b32(&m, msg32, NULL);
if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &r, &s, &q, &m, recid)) {
secp256k1_pubkey_save(pubkey, &q);
@@ -190,4 +190,4 @@ int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubk
}
}
-#endif
+#endif /* SECP256K1_MODULE_RECOVERY_MAIN_H */
diff --git a/src/secp256k1/src/modules/recovery/tests_impl.h b/src/secp256k1/src/modules/recovery/tests_impl.h
index 8932d5f0af..5c9bbe8610 100644
--- a/src/secp256k1/src/modules/recovery/tests_impl.h
+++ b/src/secp256k1/src/modules/recovery/tests_impl.h
@@ -4,8 +4,148 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_MODULE_RECOVERY_TESTS_
-#define _SECP256K1_MODULE_RECOVERY_TESTS_
+#ifndef SECP256K1_MODULE_RECOVERY_TESTS_H
+#define SECP256K1_MODULE_RECOVERY_TESTS_H
+
+static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
+ (void) msg32;
+ (void) key32;
+ (void) algo16;
+ (void) data;
+
+ /* On the first run, return 0 to force a second run */
+ if (counter == 0) {
+ memset(nonce32, 0, 32);
+ return 1;
+ }
+ /* On the second run, return an overflow to force a third run */
+ if (counter == 1) {
+ memset(nonce32, 0xff, 32);
+ return 1;
+ }
+ /* On the next run, return a valid nonce, but flip a coin as to whether or not to fail signing. */
+ memset(nonce32, 1, 32);
+ return secp256k1_rand_bits(1);
+}
+
+void test_ecdsa_recovery_api(void) {
+ /* Setup contexts that just count errors */
+ secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
+ secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
+ secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
+ secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
+ secp256k1_pubkey pubkey;
+ secp256k1_pubkey recpubkey;
+ secp256k1_ecdsa_signature normal_sig;
+ secp256k1_ecdsa_recoverable_signature recsig;
+ unsigned char privkey[32] = { 1 };
+ unsigned char message[32] = { 2 };
+ int32_t ecount = 0;
+ int recid = 0;
+ unsigned char sig[74];
+ unsigned char zero_privkey[32] = { 0 };
+ unsigned char over_privkey[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
+ secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount);
+
+ /* Construct and verify corresponding public key. */
+ CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1);
+ CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
+
+ /* Check bad contexts and NULLs for signing */
+ ecount = 0;
+ CHECK(secp256k1_ecdsa_sign_recoverable(none, &recsig, message, privkey, NULL, NULL) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_ecdsa_sign_recoverable(sign, &recsig, message, privkey, NULL, NULL) == 1);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_ecdsa_sign_recoverable(vrfy, &recsig, message, privkey, NULL, NULL) == 0);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ecdsa_sign_recoverable(both, NULL, message, privkey, NULL, NULL) == 0);
+ CHECK(ecount == 3);
+ CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, NULL, privkey, NULL, NULL) == 0);
+ CHECK(ecount == 4);
+ CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, NULL, NULL, NULL) == 0);
+ CHECK(ecount == 5);
+ /* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */
+ secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, recovery_test_nonce_function, NULL);
+ CHECK(ecount == 5);
+ /* These will all fail, but not in ARG_CHECK way */
+ CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, zero_privkey, NULL, NULL) == 0);
+ CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, over_privkey, NULL, NULL) == 0);
+ /* This one will succeed. */
+ CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
+ CHECK(ecount == 5);
+
+ /* Check signing with a goofy nonce function */
+
+ /* Check bad contexts and NULLs for recovery */
+ ecount = 0;
+ CHECK(secp256k1_ecdsa_recover(none, &recpubkey, &recsig, message) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_ecdsa_recover(sign, &recpubkey, &recsig, message) == 0);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ecdsa_recover(vrfy, &recpubkey, &recsig, message) == 1);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, message) == 1);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ecdsa_recover(both, NULL, &recsig, message) == 0);
+ CHECK(ecount == 3);
+ CHECK(secp256k1_ecdsa_recover(both, &recpubkey, NULL, message) == 0);
+ CHECK(ecount == 4);
+ CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, NULL) == 0);
+ CHECK(ecount == 5);
+
+ /* Check NULLs for conversion */
+ CHECK(secp256k1_ecdsa_sign(both, &normal_sig, message, privkey, NULL, NULL) == 1);
+ ecount = 0;
+ CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, NULL, &recsig) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, NULL) == 0);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, &recsig) == 1);
+
+ /* Check NULLs for de/serialization */
+ CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
+ ecount = 0;
+ CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, NULL, &recid, &recsig) == 0);
+ CHECK(ecount == 1);
+ CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, NULL, &recsig) == 0);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, NULL) == 0);
+ CHECK(ecount == 3);
+ CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, &recsig) == 1);
+
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, NULL, sig, recid) == 0);
+ CHECK(ecount == 4);
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, NULL, recid) == 0);
+ CHECK(ecount == 5);
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, -1) == 0);
+ CHECK(ecount == 6);
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, 5) == 0);
+ CHECK(ecount == 7);
+ /* overflow in signature will fail but not affect ecount */
+ memcpy(sig, over_privkey, 32);
+ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, recid) == 0);
+ CHECK(ecount == 7);
+
+ /* cleanup */
+ secp256k1_context_destroy(none);
+ secp256k1_context_destroy(sign);
+ secp256k1_context_destroy(vrfy);
+ secp256k1_context_destroy(both);
+}
void test_ecdsa_recovery_end_to_end(void) {
unsigned char extra[32] = {0x00};
@@ -241,10 +381,13 @@ void test_ecdsa_recovery_edge_cases(void) {
void run_recovery_tests(void) {
int i;
+ for (i = 0; i < count; i++) {
+ test_ecdsa_recovery_api();
+ }
for (i = 0; i < 64*count; i++) {
test_ecdsa_recovery_end_to_end();
}
test_ecdsa_recovery_edge_cases();
}
-#endif
+#endif /* SECP256K1_MODULE_RECOVERY_TESTS_H */
diff --git a/src/secp256k1/src/num.h b/src/secp256k1/src/num.h
index 7bb9c5be8c..49f2dd791d 100644
--- a/src/secp256k1/src/num.h
+++ b/src/secp256k1/src/num.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_NUM_
-#define _SECP256K1_NUM_
+#ifndef SECP256K1_NUM_H
+#define SECP256K1_NUM_H
#ifndef USE_NUM_NONE
@@ -71,4 +71,4 @@ static void secp256k1_num_negate(secp256k1_num *r);
#endif
-#endif
+#endif /* SECP256K1_NUM_H */
diff --git a/src/secp256k1/src/num_gmp.h b/src/secp256k1/src/num_gmp.h
index 7dd813088a..3619844bd5 100644
--- a/src/secp256k1/src/num_gmp.h
+++ b/src/secp256k1/src/num_gmp.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_NUM_REPR_
-#define _SECP256K1_NUM_REPR_
+#ifndef SECP256K1_NUM_REPR_H
+#define SECP256K1_NUM_REPR_H
#include <gmp.h>
@@ -17,4 +17,4 @@ typedef struct {
int limbs;
} secp256k1_num;
-#endif
+#endif /* SECP256K1_NUM_REPR_H */
diff --git a/src/secp256k1/src/num_gmp_impl.h b/src/secp256k1/src/num_gmp_impl.h
index 3a46495eea..0ae2a8ba0e 100644
--- a/src/secp256k1/src/num_gmp_impl.h
+++ b/src/secp256k1/src/num_gmp_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_NUM_REPR_IMPL_H_
-#define _SECP256K1_NUM_REPR_IMPL_H_
+#ifndef SECP256K1_NUM_REPR_IMPL_H
+#define SECP256K1_NUM_REPR_IMPL_H
#include <string.h>
#include <stdlib.h>
@@ -285,4 +285,4 @@ static void secp256k1_num_negate(secp256k1_num *r) {
r->neg ^= 1;
}
-#endif
+#endif /* SECP256K1_NUM_REPR_IMPL_H */
diff --git a/src/secp256k1/src/num_impl.h b/src/secp256k1/src/num_impl.h
index 0b0e3a072a..c45193b033 100644
--- a/src/secp256k1/src/num_impl.h
+++ b/src/secp256k1/src/num_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_NUM_IMPL_H_
-#define _SECP256K1_NUM_IMPL_H_
+#ifndef SECP256K1_NUM_IMPL_H
+#define SECP256K1_NUM_IMPL_H
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
@@ -21,4 +21,4 @@
#error "Please select num implementation"
#endif
-#endif
+#endif /* SECP256K1_NUM_IMPL_H */
diff --git a/src/secp256k1/src/scalar.h b/src/secp256k1/src/scalar.h
index 27e9d8375e..59304cb66e 100644
--- a/src/secp256k1/src/scalar.h
+++ b/src/secp256k1/src/scalar.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_SCALAR_
-#define _SECP256K1_SCALAR_
+#ifndef SECP256K1_SCALAR_H
+#define SECP256K1_SCALAR_H
#include "num.h"
@@ -103,4 +103,4 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar
/** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */
static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift);
-#endif
+#endif /* SECP256K1_SCALAR_H */
diff --git a/src/secp256k1/src/scalar_4x64.h b/src/secp256k1/src/scalar_4x64.h
index cff406038f..19c7495d1c 100644
--- a/src/secp256k1/src/scalar_4x64.h
+++ b/src/secp256k1/src/scalar_4x64.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_SCALAR_REPR_
-#define _SECP256K1_SCALAR_REPR_
+#ifndef SECP256K1_SCALAR_REPR_H
+#define SECP256K1_SCALAR_REPR_H
#include <stdint.h>
@@ -16,4 +16,4 @@ typedef struct {
#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{((uint64_t)(d1)) << 32 | (d0), ((uint64_t)(d3)) << 32 | (d2), ((uint64_t)(d5)) << 32 | (d4), ((uint64_t)(d7)) << 32 | (d6)}}
-#endif
+#endif /* SECP256K1_SCALAR_REPR_H */
diff --git a/src/secp256k1/src/scalar_4x64_impl.h b/src/secp256k1/src/scalar_4x64_impl.h
index 56e7bd82af..db1ebf94be 100644
--- a/src/secp256k1/src/scalar_4x64_impl.h
+++ b/src/secp256k1/src/scalar_4x64_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_
-#define _SECP256K1_SCALAR_REPR_IMPL_H_
+#ifndef SECP256K1_SCALAR_REPR_IMPL_H
+#define SECP256K1_SCALAR_REPR_IMPL_H
/* Limbs of the secp256k1 order. */
#define SECP256K1_N_0 ((uint64_t)0xBFD25E8CD0364141ULL)
@@ -946,4 +946,4 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1);
}
-#endif
+#endif /* SECP256K1_SCALAR_REPR_IMPL_H */
diff --git a/src/secp256k1/src/scalar_8x32.h b/src/secp256k1/src/scalar_8x32.h
index 1319664f65..2c9a348e24 100644
--- a/src/secp256k1/src/scalar_8x32.h
+++ b/src/secp256k1/src/scalar_8x32.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_SCALAR_REPR_
-#define _SECP256K1_SCALAR_REPR_
+#ifndef SECP256K1_SCALAR_REPR_H
+#define SECP256K1_SCALAR_REPR_H
#include <stdint.h>
@@ -16,4 +16,4 @@ typedef struct {
#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7)}}
-#endif
+#endif /* SECP256K1_SCALAR_REPR_H */
diff --git a/src/secp256k1/src/scalar_8x32_impl.h b/src/secp256k1/src/scalar_8x32_impl.h
index aae4f35c08..4f9ed61fea 100644
--- a/src/secp256k1/src/scalar_8x32_impl.h
+++ b/src/secp256k1/src/scalar_8x32_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_
-#define _SECP256K1_SCALAR_REPR_IMPL_H_
+#ifndef SECP256K1_SCALAR_REPR_IMPL_H
+#define SECP256K1_SCALAR_REPR_IMPL_H
/* Limbs of the secp256k1 order. */
#define SECP256K1_N_0 ((uint32_t)0xD0364141UL)
@@ -718,4 +718,4 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1);
}
-#endif
+#endif /* SECP256K1_SCALAR_REPR_IMPL_H */
diff --git a/src/secp256k1/src/scalar_impl.h b/src/secp256k1/src/scalar_impl.h
index f5b2376407..fa790570ff 100644
--- a/src/secp256k1/src/scalar_impl.h
+++ b/src/secp256k1/src/scalar_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_SCALAR_IMPL_H_
-#define _SECP256K1_SCALAR_IMPL_H_
+#ifndef SECP256K1_SCALAR_IMPL_H
+#define SECP256K1_SCALAR_IMPL_H
#include "group.h"
#include "scalar.h"
@@ -66,88 +66,79 @@ static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar
#else
secp256k1_scalar *t;
int i;
- /* First compute x ^ (2^N - 1) for some values of N. */
- secp256k1_scalar x2, x3, x4, x6, x7, x8, x15, x30, x60, x120, x127;
+ /* First compute xN as x ^ (2^N - 1) for some values of N,
+ * and uM as x ^ M for some values of M. */
+ secp256k1_scalar x2, x3, x6, x8, x14, x28, x56, x112, x126;
+ secp256k1_scalar u2, u5, u9, u11, u13;
- secp256k1_scalar_sqr(&x2, x);
- secp256k1_scalar_mul(&x2, &x2, x);
+ secp256k1_scalar_sqr(&u2, x);
+ secp256k1_scalar_mul(&x2, &u2, x);
+ secp256k1_scalar_mul(&u5, &u2, &x2);
+ secp256k1_scalar_mul(&x3, &u5, &u2);
+ secp256k1_scalar_mul(&u9, &x3, &u2);
+ secp256k1_scalar_mul(&u11, &u9, &u2);
+ secp256k1_scalar_mul(&u13, &u11, &u2);
- secp256k1_scalar_sqr(&x3, &x2);
- secp256k1_scalar_mul(&x3, &x3, x);
-
- secp256k1_scalar_sqr(&x4, &x3);
- secp256k1_scalar_mul(&x4, &x4, x);
-
- secp256k1_scalar_sqr(&x6, &x4);
+ secp256k1_scalar_sqr(&x6, &u13);
secp256k1_scalar_sqr(&x6, &x6);
- secp256k1_scalar_mul(&x6, &x6, &x2);
+ secp256k1_scalar_mul(&x6, &x6, &u11);
- secp256k1_scalar_sqr(&x7, &x6);
- secp256k1_scalar_mul(&x7, &x7, x);
+ secp256k1_scalar_sqr(&x8, &x6);
+ secp256k1_scalar_sqr(&x8, &x8);
+ secp256k1_scalar_mul(&x8, &x8, &x2);
- secp256k1_scalar_sqr(&x8, &x7);
- secp256k1_scalar_mul(&x8, &x8, x);
-
- secp256k1_scalar_sqr(&x15, &x8);
- for (i = 0; i < 6; i++) {
- secp256k1_scalar_sqr(&x15, &x15);
+ secp256k1_scalar_sqr(&x14, &x8);
+ for (i = 0; i < 5; i++) {
+ secp256k1_scalar_sqr(&x14, &x14);
}
- secp256k1_scalar_mul(&x15, &x15, &x7);
+ secp256k1_scalar_mul(&x14, &x14, &x6);
- secp256k1_scalar_sqr(&x30, &x15);
- for (i = 0; i < 14; i++) {
- secp256k1_scalar_sqr(&x30, &x30);
+ secp256k1_scalar_sqr(&x28, &x14);
+ for (i = 0; i < 13; i++) {
+ secp256k1_scalar_sqr(&x28, &x28);
}
- secp256k1_scalar_mul(&x30, &x30, &x15);
+ secp256k1_scalar_mul(&x28, &x28, &x14);
- secp256k1_scalar_sqr(&x60, &x30);
- for (i = 0; i < 29; i++) {
- secp256k1_scalar_sqr(&x60, &x60);
+ secp256k1_scalar_sqr(&x56, &x28);
+ for (i = 0; i < 27; i++) {
+ secp256k1_scalar_sqr(&x56, &x56);
}
- secp256k1_scalar_mul(&x60, &x60, &x30);
+ secp256k1_scalar_mul(&x56, &x56, &x28);
- secp256k1_scalar_sqr(&x120, &x60);
- for (i = 0; i < 59; i++) {
- secp256k1_scalar_sqr(&x120, &x120);
+ secp256k1_scalar_sqr(&x112, &x56);
+ for (i = 0; i < 55; i++) {
+ secp256k1_scalar_sqr(&x112, &x112);
}
- secp256k1_scalar_mul(&x120, &x120, &x60);
+ secp256k1_scalar_mul(&x112, &x112, &x56);
- secp256k1_scalar_sqr(&x127, &x120);
- for (i = 0; i < 6; i++) {
- secp256k1_scalar_sqr(&x127, &x127);
+ secp256k1_scalar_sqr(&x126, &x112);
+ for (i = 0; i < 13; i++) {
+ secp256k1_scalar_sqr(&x126, &x126);
}
- secp256k1_scalar_mul(&x127, &x127, &x7);
+ secp256k1_scalar_mul(&x126, &x126, &x14);
- /* Then accumulate the final result (t starts at x127). */
- t = &x127;
- for (i = 0; i < 2; i++) { /* 0 */
+ /* Then accumulate the final result (t starts at x126). */
+ t = &x126;
+ for (i = 0; i < 3; i++) {
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, x); /* 1 */
+ secp256k1_scalar_mul(t, t, &u5); /* 101 */
for (i = 0; i < 4; i++) { /* 0 */
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &x3); /* 111 */
- for (i = 0; i < 2; i++) { /* 0 */
- secp256k1_scalar_sqr(t, t);
- }
- secp256k1_scalar_mul(t, t, x); /* 1 */
- for (i = 0; i < 2; i++) { /* 0 */
- secp256k1_scalar_sqr(t, t);
- }
- secp256k1_scalar_mul(t, t, x); /* 1 */
- for (i = 0; i < 2; i++) { /* 0 */
+ for (i = 0; i < 4; i++) { /* 0 */
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, x); /* 1 */
- for (i = 0; i < 4; i++) { /* 0 */
+ secp256k1_scalar_mul(t, t, &u5); /* 101 */
+ for (i = 0; i < 5; i++) { /* 0 */
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, &x3); /* 111 */
- for (i = 0; i < 3; i++) { /* 0 */
+ secp256k1_scalar_mul(t, t, &u11); /* 1011 */
+ for (i = 0; i < 4; i++) {
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, &x2); /* 11 */
+ secp256k1_scalar_mul(t, t, &u11); /* 1011 */
for (i = 0; i < 4; i++) { /* 0 */
secp256k1_scalar_sqr(t, t);
}
@@ -156,38 +147,26 @@ static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &x3); /* 111 */
- for (i = 0; i < 4; i++) { /* 00 */
+ for (i = 0; i < 6; i++) { /* 00 */
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, &x2); /* 11 */
- for (i = 0; i < 2; i++) { /* 0 */
+ secp256k1_scalar_mul(t, t, &u13); /* 1101 */
+ for (i = 0; i < 4; i++) { /* 0 */
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, x); /* 1 */
- for (i = 0; i < 2; i++) { /* 0 */
+ secp256k1_scalar_mul(t, t, &u5); /* 101 */
+ for (i = 0; i < 3; i++) {
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, x); /* 1 */
+ secp256k1_scalar_mul(t, t, &x3); /* 111 */
for (i = 0; i < 5; i++) { /* 0 */
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, &x4); /* 1111 */
- for (i = 0; i < 2; i++) { /* 0 */
- secp256k1_scalar_sqr(t, t);
- }
- secp256k1_scalar_mul(t, t, x); /* 1 */
- for (i = 0; i < 3; i++) { /* 00 */
+ secp256k1_scalar_mul(t, t, &u9); /* 1001 */
+ for (i = 0; i < 6; i++) { /* 000 */
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, x); /* 1 */
- for (i = 0; i < 4; i++) { /* 000 */
- secp256k1_scalar_sqr(t, t);
- }
- secp256k1_scalar_mul(t, t, x); /* 1 */
- for (i = 0; i < 2; i++) { /* 0 */
- secp256k1_scalar_sqr(t, t);
- }
- secp256k1_scalar_mul(t, t, x); /* 1 */
+ secp256k1_scalar_mul(t, t, &u5); /* 101 */
for (i = 0; i < 10; i++) { /* 0000000 */
secp256k1_scalar_sqr(t, t);
}
@@ -200,50 +179,34 @@ static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &x8); /* 11111111 */
- for (i = 0; i < 2; i++) { /* 0 */
- secp256k1_scalar_sqr(t, t);
- }
- secp256k1_scalar_mul(t, t, x); /* 1 */
- for (i = 0; i < 3; i++) { /* 00 */
- secp256k1_scalar_sqr(t, t);
- }
- secp256k1_scalar_mul(t, t, x); /* 1 */
- for (i = 0; i < 3; i++) { /* 00 */
- secp256k1_scalar_sqr(t, t);
- }
- secp256k1_scalar_mul(t, t, x); /* 1 */
for (i = 0; i < 5; i++) { /* 0 */
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, &x4); /* 1111 */
- for (i = 0; i < 2; i++) { /* 0 */
+ secp256k1_scalar_mul(t, t, &u9); /* 1001 */
+ for (i = 0; i < 6; i++) { /* 00 */
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, x); /* 1 */
- for (i = 0; i < 5; i++) { /* 000 */
+ secp256k1_scalar_mul(t, t, &u11); /* 1011 */
+ for (i = 0; i < 4; i++) {
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, &x2); /* 11 */
- for (i = 0; i < 4; i++) { /* 00 */
+ secp256k1_scalar_mul(t, t, &u13); /* 1101 */
+ for (i = 0; i < 5; i++) {
secp256k1_scalar_sqr(t, t);
}
secp256k1_scalar_mul(t, t, &x2); /* 11 */
- for (i = 0; i < 2; i++) { /* 0 */
- secp256k1_scalar_sqr(t, t);
- }
- secp256k1_scalar_mul(t, t, x); /* 1 */
- for (i = 0; i < 8; i++) { /* 000000 */
+ for (i = 0; i < 6; i++) { /* 00 */
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, &x2); /* 11 */
- for (i = 0; i < 3; i++) { /* 0 */
+ secp256k1_scalar_mul(t, t, &u13); /* 1101 */
+ for (i = 0; i < 10; i++) { /* 000000 */
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, &x2); /* 11 */
- for (i = 0; i < 3; i++) { /* 00 */
+ secp256k1_scalar_mul(t, t, &u13); /* 1101 */
+ for (i = 0; i < 4; i++) {
secp256k1_scalar_sqr(t, t);
}
- secp256k1_scalar_mul(t, t, x); /* 1 */
+ secp256k1_scalar_mul(t, t, &u9); /* 1001 */
for (i = 0; i < 6; i++) { /* 00000 */
secp256k1_scalar_sqr(t, t);
}
@@ -367,4 +330,4 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar
#endif
#endif
-#endif
+#endif /* SECP256K1_SCALAR_IMPL_H */
diff --git a/src/secp256k1/src/scalar_low.h b/src/secp256k1/src/scalar_low.h
index 5574c44c7a..5836febc5b 100644
--- a/src/secp256k1/src/scalar_low.h
+++ b/src/secp256k1/src/scalar_low.h
@@ -4,12 +4,12 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_SCALAR_REPR_
-#define _SECP256K1_SCALAR_REPR_
+#ifndef SECP256K1_SCALAR_REPR_H
+#define SECP256K1_SCALAR_REPR_H
#include <stdint.h>
/** A scalar modulo the group order of the secp256k1 curve. */
typedef uint32_t secp256k1_scalar;
-#endif
+#endif /* SECP256K1_SCALAR_REPR_H */
diff --git a/src/secp256k1/src/scalar_low_impl.h b/src/secp256k1/src/scalar_low_impl.h
index 4f94441f49..c80e70c5a2 100644
--- a/src/secp256k1/src/scalar_low_impl.h
+++ b/src/secp256k1/src/scalar_low_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_
-#define _SECP256K1_SCALAR_REPR_IMPL_H_
+#ifndef SECP256K1_SCALAR_REPR_IMPL_H
+#define SECP256K1_SCALAR_REPR_IMPL_H
#include "scalar.h"
@@ -111,4 +111,4 @@ SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const
return *a == *b;
}
-#endif
+#endif /* SECP256K1_SCALAR_REPR_IMPL_H */
diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c
index fb8b882faa..4f8c01655b 100755..100644
--- a/src/secp256k1/src/secp256k1.c
+++ b/src/secp256k1/src/secp256k1.c
@@ -424,6 +424,33 @@ int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *p
return ret;
}
+int secp256k1_ec_privkey_negate(const secp256k1_context* ctx, unsigned char *seckey) {
+ secp256k1_scalar sec;
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(seckey != NULL);
+
+ secp256k1_scalar_set_b32(&sec, seckey, NULL);
+ secp256k1_scalar_negate(&sec, &sec);
+ secp256k1_scalar_get_b32(seckey, &sec);
+
+ return 1;
+}
+
+int secp256k1_ec_pubkey_negate(const secp256k1_context* ctx, secp256k1_pubkey *pubkey) {
+ int ret = 0;
+ secp256k1_ge p;
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(pubkey != NULL);
+
+ ret = secp256k1_pubkey_load(ctx, &p, pubkey);
+ memset(pubkey, 0, sizeof(*pubkey));
+ if (ret) {
+ secp256k1_ge_neg(&p, &p);
+ secp256k1_pubkey_save(pubkey, &p);
+ }
+ return ret;
+}
+
int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) {
secp256k1_scalar term;
secp256k1_scalar sec;
@@ -552,10 +579,6 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey *
# include "modules/ecdh/main_impl.h"
#endif
-#ifdef ENABLE_MODULE_SCHNORR
-# include "modules/schnorr/main_impl.h"
-#endif
-
#ifdef ENABLE_MODULE_RECOVERY
# include "modules/recovery/main_impl.h"
#endif
diff --git a/src/secp256k1/src/testrand.h b/src/secp256k1/src/testrand.h
index f8efa93c7c..f1f9be077e 100644
--- a/src/secp256k1/src/testrand.h
+++ b/src/secp256k1/src/testrand.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_TESTRAND_H_
-#define _SECP256K1_TESTRAND_H_
+#ifndef SECP256K1_TESTRAND_H
+#define SECP256K1_TESTRAND_H
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
@@ -35,4 +35,4 @@ static void secp256k1_rand256_test(unsigned char *b32);
/** Generate pseudorandom bytes with long sequences of zero and one bits. */
static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len);
-#endif
+#endif /* SECP256K1_TESTRAND_H */
diff --git a/src/secp256k1/src/testrand_impl.h b/src/secp256k1/src/testrand_impl.h
index 15c7b9f12d..1255574209 100644
--- a/src/secp256k1/src/testrand_impl.h
+++ b/src/secp256k1/src/testrand_impl.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_TESTRAND_IMPL_H_
-#define _SECP256K1_TESTRAND_IMPL_H_
+#ifndef SECP256K1_TESTRAND_IMPL_H
+#define SECP256K1_TESTRAND_IMPL_H
#include <stdint.h>
#include <string.h>
@@ -107,4 +107,4 @@ static void secp256k1_rand256_test(unsigned char *b32) {
secp256k1_rand_bytes_test(b32, 32);
}
-#endif
+#endif /* SECP256K1_TESTRAND_IMPL_H */
diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c
index 9ae7d30281..3d9bd5ebb4 100644
--- a/src/secp256k1/src/tests.c
+++ b/src/secp256k1/src/tests.c
@@ -10,6 +10,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <time.h>
@@ -135,6 +136,7 @@ void random_scalar_order(secp256k1_scalar *num) {
void run_context_tests(void) {
secp256k1_pubkey pubkey;
+ secp256k1_pubkey zero_pubkey;
secp256k1_ecdsa_signature sig;
unsigned char ctmp[32];
int32_t ecount;
@@ -149,6 +151,8 @@ void run_context_tests(void) {
secp256k1_scalar msg, key, nonce;
secp256k1_scalar sigr, sigs;
+ memset(&zero_pubkey, 0, sizeof(zero_pubkey));
+
ecount = 0;
ecount2 = 10;
secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
@@ -201,12 +205,20 @@ void run_context_tests(void) {
CHECK(ecount == 2);
CHECK(secp256k1_ec_pubkey_tweak_mul(sign, &pubkey, ctmp) == 0);
CHECK(ecount2 == 13);
- CHECK(secp256k1_ec_pubkey_tweak_mul(vrfy, &pubkey, ctmp) == 1);
+ CHECK(secp256k1_ec_pubkey_negate(vrfy, &pubkey) == 1);
CHECK(ecount == 2);
- CHECK(secp256k1_context_randomize(vrfy, ctmp) == 0);
+ CHECK(secp256k1_ec_pubkey_negate(sign, &pubkey) == 1);
+ CHECK(ecount == 2);
+ CHECK(secp256k1_ec_pubkey_negate(sign, NULL) == 0);
+ CHECK(ecount2 == 14);
+ CHECK(secp256k1_ec_pubkey_negate(vrfy, &zero_pubkey) == 0);
CHECK(ecount == 3);
+ CHECK(secp256k1_ec_pubkey_tweak_mul(vrfy, &pubkey, ctmp) == 1);
+ CHECK(ecount == 3);
+ CHECK(secp256k1_context_randomize(vrfy, ctmp) == 0);
+ CHECK(ecount == 4);
CHECK(secp256k1_context_randomize(sign, NULL) == 1);
- CHECK(ecount2 == 13);
+ CHECK(ecount2 == 14);
secp256k1_context_set_illegal_callback(vrfy, NULL, NULL);
secp256k1_context_set_illegal_callback(sign, NULL, NULL);
@@ -1879,9 +1891,9 @@ void test_ge(void) {
*
* When the endomorphism code is compiled in, p5 = lambda*p1 and p6 = lambda^2*p1 are added as well.
*/
- secp256k1_ge *ge = (secp256k1_ge *)malloc(sizeof(secp256k1_ge) * (1 + 4 * runs));
- secp256k1_gej *gej = (secp256k1_gej *)malloc(sizeof(secp256k1_gej) * (1 + 4 * runs));
- secp256k1_fe *zinv = (secp256k1_fe *)malloc(sizeof(secp256k1_fe) * (1 + 4 * runs));
+ secp256k1_ge *ge = (secp256k1_ge *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_ge) * (1 + 4 * runs));
+ secp256k1_gej *gej = (secp256k1_gej *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_gej) * (1 + 4 * runs));
+ secp256k1_fe *zinv = (secp256k1_fe *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_fe) * (1 + 4 * runs));
secp256k1_fe zf;
secp256k1_fe zfi2, zfi3;
@@ -1919,7 +1931,7 @@ void test_ge(void) {
/* Compute z inverses. */
{
- secp256k1_fe *zs = malloc(sizeof(secp256k1_fe) * (1 + 4 * runs));
+ secp256k1_fe *zs = checked_malloc(&ctx->error_callback, sizeof(secp256k1_fe) * (1 + 4 * runs));
for (i = 0; i < 4 * runs + 1; i++) {
if (i == 0) {
/* The point at infinity does not have a meaningful z inverse. Any should do. */
@@ -2020,7 +2032,7 @@ void test_ge(void) {
/* Test adding all points together in random order equals infinity. */
{
secp256k1_gej sum = SECP256K1_GEJ_CONST_INFINITY;
- secp256k1_gej *gej_shuffled = (secp256k1_gej *)malloc((4 * runs + 1) * sizeof(secp256k1_gej));
+ secp256k1_gej *gej_shuffled = (secp256k1_gej *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_gej));
for (i = 0; i < 4 * runs + 1; i++) {
gej_shuffled[i] = gej[i];
}
@@ -2041,9 +2053,9 @@ void test_ge(void) {
/* Test batch gej -> ge conversion with and without known z ratios. */
{
- secp256k1_fe *zr = (secp256k1_fe *)malloc((4 * runs + 1) * sizeof(secp256k1_fe));
- secp256k1_ge *ge_set_table = (secp256k1_ge *)malloc((4 * runs + 1) * sizeof(secp256k1_ge));
- secp256k1_ge *ge_set_all = (secp256k1_ge *)malloc((4 * runs + 1) * sizeof(secp256k1_ge));
+ secp256k1_fe *zr = (secp256k1_fe *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_fe));
+ secp256k1_ge *ge_set_table = (secp256k1_ge *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge));
+ secp256k1_ge *ge_set_all = (secp256k1_ge *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge));
for (i = 0; i < 4 * runs + 1; i++) {
/* Compute gej[i + 1].z / gez[i].z (with gej[n].z taken to be 1). */
if (i < 4 * runs) {
@@ -3436,6 +3448,7 @@ void test_ecdsa_end_to_end(void) {
unsigned char pubkeyc[65];
size_t pubkeyclen = 65;
secp256k1_pubkey pubkey;
+ secp256k1_pubkey pubkey_tmp;
unsigned char seckey[300];
size_t seckeylen = 300;
@@ -3457,6 +3470,13 @@ void test_ecdsa_end_to_end(void) {
memset(&pubkey, 0, sizeof(pubkey));
CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1);
+ /* Verify negation changes the key and changes it back */
+ memcpy(&pubkey_tmp, &pubkey, sizeof(pubkey));
+ CHECK(secp256k1_ec_pubkey_negate(ctx, &pubkey_tmp) == 1);
+ CHECK(memcmp(&pubkey_tmp, &pubkey, sizeof(pubkey)) != 0);
+ CHECK(secp256k1_ec_pubkey_negate(ctx, &pubkey_tmp) == 1);
+ CHECK(memcmp(&pubkey_tmp, &pubkey, sizeof(pubkey)) == 0);
+
/* Verify private key import and export. */
CHECK(ec_privkey_export_der(ctx, seckey, &seckeylen, privkey, secp256k1_rand_bits(1) == 1));
CHECK(ec_privkey_import_der(ctx, privkey2, seckey, seckeylen) == 1);
@@ -4383,10 +4403,6 @@ void run_ecdsa_openssl(void) {
# include "modules/ecdh/tests_impl.h"
#endif
-#ifdef ENABLE_MODULE_SCHNORR
-# include "modules/schnorr/tests_impl.h"
-#endif
-
#ifdef ENABLE_MODULE_RECOVERY
# include "modules/recovery/tests_impl.h"
#endif
@@ -4504,11 +4520,6 @@ int main(int argc, char **argv) {
run_ecdsa_openssl();
#endif
-#ifdef ENABLE_MODULE_SCHNORR
- /* Schnorr tests */
- run_schnorr_tests();
-#endif
-
#ifdef ENABLE_MODULE_RECOVERY
/* ECDSA pubkey recovery tests */
run_recovery_tests();
diff --git a/src/secp256k1/src/tests_exhaustive.c b/src/secp256k1/src/tests_exhaustive.c
index bda6ee475c..b040bb0733 100644
--- a/src/secp256k1/src/tests_exhaustive.c
+++ b/src/secp256k1/src/tests_exhaustive.c
@@ -26,6 +26,11 @@
#include "secp256k1.c"
#include "testrand_impl.h"
+#ifdef ENABLE_MODULE_RECOVERY
+#include "src/modules/recovery/main_impl.h"
+#include "include/secp256k1_recovery.h"
+#endif
+
/** stolen from tests.c */
void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) {
CHECK(a->infinity == b->infinity);
@@ -77,7 +82,7 @@ int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned cha
* function with an increased `attempt`. So if attempt > 0 this means we
* need to change the nonce to avoid an infinite loop. */
if (attempt > 0) {
- (*idata)++;
+ *idata = (*idata + 1) % EXHAUSTIVE_TEST_ORDER;
}
secp256k1_scalar_set_int(&s, *idata);
secp256k1_scalar_get_b32(nonce32, &s);
@@ -244,6 +249,7 @@ void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *grou
for (i = 1; i < order; i++) { /* message */
for (j = 1; j < order; j++) { /* key */
for (k = 1; k < order; k++) { /* nonce */
+ const int starting_k = k;
secp256k1_ecdsa_signature sig;
secp256k1_scalar sk, msg, r, s, expected_r;
unsigned char sk32[32], msg32[32];
@@ -262,6 +268,11 @@ void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *grou
CHECK(r == expected_r);
CHECK((k * s) % order == (i + r * j) % order ||
(k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order);
+
+ /* Overflow means we've tried every possible nonce */
+ if (k < starting_k) {
+ break;
+ }
}
}
}
@@ -276,6 +287,130 @@ void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *grou
*/
}
+#ifdef ENABLE_MODULE_RECOVERY
+void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group, int order) {
+ int i, j, k;
+
+ /* Loop */
+ for (i = 1; i < order; i++) { /* message */
+ for (j = 1; j < order; j++) { /* key */
+ for (k = 1; k < order; k++) { /* nonce */
+ const int starting_k = k;
+ secp256k1_fe r_dot_y_normalized;
+ secp256k1_ecdsa_recoverable_signature rsig;
+ secp256k1_ecdsa_signature sig;
+ secp256k1_scalar sk, msg, r, s, expected_r;
+ unsigned char sk32[32], msg32[32];
+ int expected_recid;
+ int recid;
+ secp256k1_scalar_set_int(&msg, i);
+ secp256k1_scalar_set_int(&sk, j);
+ secp256k1_scalar_get_b32(sk32, &sk);
+ secp256k1_scalar_get_b32(msg32, &msg);
+
+ secp256k1_ecdsa_sign_recoverable(ctx, &rsig, msg32, sk32, secp256k1_nonce_function_smallint, &k);
+
+ /* Check directly */
+ secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, &rsig);
+ r_from_k(&expected_r, group, k);
+ CHECK(r == expected_r);
+ CHECK((k * s) % order == (i + r * j) % order ||
+ (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order);
+ /* In computing the recid, there is an overflow condition that is disabled in
+ * scalar_low_impl.h `secp256k1_scalar_set_b32` because almost every r.y value
+ * will exceed the group order, and our signing code always holds out for r
+ * values that don't overflow, so with a proper overflow check the tests would
+ * loop indefinitely. */
+ r_dot_y_normalized = group[k].y;
+ secp256k1_fe_normalize(&r_dot_y_normalized);
+ /* Also the recovery id is flipped depending if we hit the low-s branch */
+ if ((k * s) % order == (i + r * j) % order) {
+ expected_recid = secp256k1_fe_is_odd(&r_dot_y_normalized) ? 1 : 0;
+ } else {
+ expected_recid = secp256k1_fe_is_odd(&r_dot_y_normalized) ? 0 : 1;
+ }
+ CHECK(recid == expected_recid);
+
+ /* Convert to a standard sig then check */
+ secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig);
+ secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig);
+ /* Note that we compute expected_r *after* signing -- this is important
+ * because our nonce-computing function function might change k during
+ * signing. */
+ r_from_k(&expected_r, group, k);
+ CHECK(r == expected_r);
+ CHECK((k * s) % order == (i + r * j) % order ||
+ (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order);
+
+ /* Overflow means we've tried every possible nonce */
+ if (k < starting_k) {
+ break;
+ }
+ }
+ }
+ }
+}
+
+void test_exhaustive_recovery_verify(const secp256k1_context *ctx, const secp256k1_ge *group, int order) {
+ /* This is essentially a copy of test_exhaustive_verify, with recovery added */
+ int s, r, msg, key;
+ for (s = 1; s < order; s++) {
+ for (r = 1; r < order; r++) {
+ for (msg = 1; msg < order; msg++) {
+ for (key = 1; key < order; key++) {
+ secp256k1_ge nonconst_ge;
+ secp256k1_ecdsa_recoverable_signature rsig;
+ secp256k1_ecdsa_signature sig;
+ secp256k1_pubkey pk;
+ secp256k1_scalar sk_s, msg_s, r_s, s_s;
+ secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s;
+ int recid = 0;
+ int k, should_verify;
+ unsigned char msg32[32];
+
+ secp256k1_scalar_set_int(&s_s, s);
+ secp256k1_scalar_set_int(&r_s, r);
+ secp256k1_scalar_set_int(&msg_s, msg);
+ secp256k1_scalar_set_int(&sk_s, key);
+ secp256k1_scalar_get_b32(msg32, &msg_s);
+
+ /* Verify by hand */
+ /* Run through every k value that gives us this r and check that *one* works.
+ * Note there could be none, there could be multiple, ECDSA is weird. */
+ should_verify = 0;
+ for (k = 0; k < order; k++) {
+ secp256k1_scalar check_x_s;
+ r_from_k(&check_x_s, group, k);
+ if (r_s == check_x_s) {
+ secp256k1_scalar_set_int(&s_times_k_s, k);
+ secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s);
+ secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s);
+ secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s);
+ should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s);
+ }
+ }
+ /* nb we have a "high s" rule */
+ should_verify &= !secp256k1_scalar_is_high(&s_s);
+
+ /* We would like to try recovering the pubkey and checking that it matches,
+ * but pubkey recovery is impossible in the exhaustive tests (the reason
+ * being that there are 12 nonzero r values, 12 nonzero points, and no
+ * overlap between the sets, so there are no valid signatures). */
+
+ /* Verify by converting to a standard signature and calling verify */
+ secp256k1_ecdsa_recoverable_signature_save(&rsig, &r_s, &s_s, recid);
+ secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig);
+ memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge));
+ secp256k1_pubkey_save(&pk, &nonconst_ge);
+ CHECK(should_verify ==
+ secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk));
+ }
+ }
+ }
+ }
+}
+#endif
+
int main(void) {
int i;
secp256k1_gej groupj[EXHAUSTIVE_TEST_ORDER];
@@ -324,6 +459,12 @@ int main(void) {
test_exhaustive_sign(ctx, group, EXHAUSTIVE_TEST_ORDER);
test_exhaustive_verify(ctx, group, EXHAUSTIVE_TEST_ORDER);
+#ifdef ENABLE_MODULE_RECOVERY
+ test_exhaustive_recovery_sign(ctx, group, EXHAUSTIVE_TEST_ORDER);
+ test_exhaustive_recovery_verify(ctx, group, EXHAUSTIVE_TEST_ORDER);
+#endif
+
+ secp256k1_context_destroy(ctx);
return 0;
}
diff --git a/src/secp256k1/src/util.h b/src/secp256k1/src/util.h
index 4eef4ded47..b0441d8e30 100644
--- a/src/secp256k1/src/util.h
+++ b/src/secp256k1/src/util.h
@@ -4,8 +4,8 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#ifndef _SECP256K1_UTIL_H_
-#define _SECP256K1_UTIL_H_
+#ifndef SECP256K1_UTIL_H
+#define SECP256K1_UTIL_H
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
@@ -57,7 +57,10 @@ static SECP256K1_INLINE void secp256k1_callback_call(const secp256k1_callback *
#endif
/* Like assert(), but when VERIFY is defined, and side-effect safe. */
-#ifdef VERIFY
+#if defined(COVERAGE)
+#define VERIFY_CHECK(check)
+#define VERIFY_SETUP(stmt)
+#elif defined(VERIFY)
#define VERIFY_CHECK CHECK
#define VERIFY_SETUP(stmt) do { stmt; } while(0)
#else
@@ -107,4 +110,4 @@ static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_
SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t;
#endif
-#endif
+#endif /* SECP256K1_UTIL_H */
diff --git a/src/serialize.h b/src/serialize.h
index e4d72d2348..eeb05fa76c 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -336,11 +336,18 @@ I ReadVarInt(Stream& is)
I n = 0;
while(true) {
unsigned char chData = ser_readdata8(is);
+ if (n > (std::numeric_limits<I>::max() >> 7)) {
+ throw std::ios_base::failure("ReadVarInt(): size too large");
+ }
n = (n << 7) | (chData & 0x7F);
- if (chData & 0x80)
+ if (chData & 0x80) {
+ if (n == std::numeric_limits<I>::max()) {
+ throw std::ios_base::failure("ReadVarInt(): size too large");
+ }
n++;
- else
+ } else {
return n;
+ }
}
}
@@ -395,7 +402,7 @@ class CVarInt
protected:
I &n;
public:
- CVarInt(I& nIn) : n(nIn) { }
+ explicit CVarInt(I& nIn) : n(nIn) { }
template<typename Stream>
void Serialize(Stream &s) const {
@@ -413,7 +420,7 @@ class CCompactSize
protected:
uint64_t &n;
public:
- CCompactSize(uint64_t& nIn) : n(nIn) { }
+ explicit CCompactSize(uint64_t& nIn) : n(nIn) { }
template<typename Stream>
void Serialize(Stream &s) const {
@@ -432,7 +439,7 @@ class LimitedString
protected:
std::string& string;
public:
- LimitedString(std::string& _string) : string(_string) {}
+ explicit LimitedString(std::string& _string) : string(_string) {}
template<typename Stream>
void Unserialize(Stream& s)
@@ -443,7 +450,7 @@ public:
}
string.resize(size);
if (size != 0)
- s.read((char*)&string[0], size);
+ s.read((char*)string.data(), size);
}
template<typename Stream>
@@ -451,7 +458,7 @@ public:
{
WriteCompactSize(s, string.size());
if (!string.empty())
- s.write((char*)&string[0], string.size());
+ s.write((char*)string.data(), string.size());
}
};
@@ -549,7 +556,7 @@ void Serialize(Stream& os, const std::basic_string<C>& str)
{
WriteCompactSize(os, str.size());
if (!str.empty())
- os.write((char*)&str[0], str.size() * sizeof(str[0]));
+ os.write((char*)str.data(), str.size() * sizeof(C));
}
template<typename Stream, typename C>
@@ -558,7 +565,7 @@ void Unserialize(Stream& is, std::basic_string<C>& str)
unsigned int nSize = ReadCompactSize(is);
str.resize(nSize);
if (nSize != 0)
- is.read((char*)&str[0], nSize * sizeof(str[0]));
+ is.read((char*)str.data(), nSize * sizeof(C));
}
@@ -571,7 +578,7 @@ void Serialize_impl(Stream& os, const prevector<N, T>& v, const unsigned char&)
{
WriteCompactSize(os, v.size());
if (!v.empty())
- os.write((char*)&v[0], v.size() * sizeof(T));
+ os.write((char*)v.data(), v.size() * sizeof(T));
}
template<typename Stream, unsigned int N, typename T, typename V>
@@ -639,7 +646,7 @@ void Serialize_impl(Stream& os, const std::vector<T, A>& v, const unsigned char&
{
WriteCompactSize(os, v.size());
if (!v.empty())
- os.write((char*)&v[0], v.size() * sizeof(T));
+ os.write((char*)v.data(), v.size() * sizeof(T));
}
template<typename Stream, typename T, typename A, typename V>
diff --git a/src/streams.h b/src/streams.h
index 1d3b55c91e..9a3badea57 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -82,7 +82,7 @@ class CVectorWriter
* @param[in] nVersionIn Serialization Version (including any flags)
* @param[in] vchDataIn Referenced byte vector to overwrite/append
* @param[in] nPosIn Starting position. Vector index where writes should start. The vector will initially
- * grow as necessary to max(index, vec.size()). So to append, use vec.size().
+ * grow as necessary to max(nPosIn, vec.size()). So to append, use vec.size().
*/
CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn) : nType(nTypeIn), nVersion(nVersionIn), vchData(vchDataIn), nPos(nPosIn)
{
@@ -91,7 +91,7 @@ class CVectorWriter
}
/*
* (other params same as above)
- * @param[in] args A list of items to serialize starting at nPos.
+ * @param[in] args A list of items to serialize starting at nPosIn.
*/
template <typename... Args>
CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn, Args&&... args) : CVectorWriter(nTypeIn, nVersionIn, vchDataIn, nPosIn)
@@ -248,7 +248,8 @@ public:
void insert(iterator it, std::vector<char>::const_iterator first, std::vector<char>::const_iterator last)
{
- assert(last - first >= 0);
+ if (last == first) return;
+ assert(last - first > 0);
if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos)
{
// special case for inserting at the front when there's room
@@ -261,7 +262,8 @@ public:
void insert(iterator it, const char* first, const char* last)
{
- assert(last - first >= 0);
+ if (last == first) return;
+ assert(last - first > 0);
if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos)
{
// special case for inserting at the front when there's room
@@ -330,7 +332,7 @@ public:
//
bool eof() const { return size() == 0; }
CDataStream* rdbuf() { return this; }
- int in_avail() { return size(); }
+ int in_avail() const { return size(); }
void SetType(int n) { nType = n; }
int GetType() const { return nType; }
@@ -339,6 +341,8 @@ public:
void read(char* pch, size_t nSize)
{
+ if (nSize == 0) return;
+
// Read from the beginning of the buffer
unsigned int nReadPosNext = nReadPos + nSize;
if (nReadPosNext >= vch.size())
@@ -385,7 +389,7 @@ public:
{
// Special case: stream << stream concatenates like stream += stream
if (!vch.empty())
- s.write((char*)&vch[0], vch.size() * sizeof(vch[0]));
+ s.write((char*)vch.data(), vch.size() * sizeof(value_type));
}
template<typename T>
@@ -404,8 +408,8 @@ public:
return (*this);
}
- void GetAndClear(CSerializeData &data) {
- data.insert(data.end(), begin(), end());
+ void GetAndClear(CSerializeData &d) {
+ d.insert(d.end(), begin(), end());
clear();
}
@@ -451,10 +455,6 @@ public:
class CAutoFile
{
private:
- // Disallow copies
- CAutoFile(const CAutoFile&);
- CAutoFile& operator=(const CAutoFile&);
-
const int nType;
const int nVersion;
@@ -471,11 +471,15 @@ public:
fclose();
}
+ // Disallow copies
+ CAutoFile(const CAutoFile&) = delete;
+ CAutoFile& operator=(const CAutoFile&) = delete;
+
void fclose()
{
if (file) {
::fclose(file);
- file = NULL;
+ file = nullptr;
}
}
@@ -483,7 +487,7 @@ public:
* @note This will invalidate the CAutoFile object, and makes it the responsibility of the caller
* of this function to clean up the returned FILE*.
*/
- FILE* release() { FILE* ret = file; file = NULL; return ret; }
+ FILE* release() { FILE* ret = file; file = nullptr; return ret; }
/** Get wrapped FILE* without transfer of ownership.
* @note Ownership of the FILE* will remain with this class. Use this only if the scope of the
@@ -491,9 +495,9 @@ public:
*/
FILE* Get() const { return file; }
- /** Return true if the wrapped FILE* is NULL, false otherwise.
+ /** Return true if the wrapped FILE* is nullptr, false otherwise.
*/
- bool IsNull() const { return (file == NULL); }
+ bool IsNull() const { return (file == nullptr); }
//
// Stream subset
@@ -504,7 +508,7 @@ public:
void read(char* pch, size_t nSize)
{
if (!file)
- throw std::ios_base::failure("CAutoFile::read: file handle is NULL");
+ throw std::ios_base::failure("CAutoFile::read: file handle is nullptr");
if (fread(pch, 1, nSize, file) != nSize)
throw std::ios_base::failure(feof(file) ? "CAutoFile::read: end of file" : "CAutoFile::read: fread failed");
}
@@ -512,7 +516,7 @@ public:
void ignore(size_t nSize)
{
if (!file)
- throw std::ios_base::failure("CAutoFile::ignore: file handle is NULL");
+ throw std::ios_base::failure("CAutoFile::ignore: file handle is nullptr");
unsigned char data[4096];
while (nSize > 0) {
size_t nNow = std::min<size_t>(nSize, sizeof(data));
@@ -525,7 +529,7 @@ public:
void write(const char* pch, size_t nSize)
{
if (!file)
- throw std::ios_base::failure("CAutoFile::write: file handle is NULL");
+ throw std::ios_base::failure("CAutoFile::write: file handle is nullptr");
if (fwrite(pch, 1, nSize, file) != nSize)
throw std::ios_base::failure("CAutoFile::write: write failed");
}
@@ -535,7 +539,7 @@ public:
{
// Serialize to this stream
if (!file)
- throw std::ios_base::failure("CAutoFile::operator<<: file handle is NULL");
+ throw std::ios_base::failure("CAutoFile::operator<<: file handle is nullptr");
::Serialize(*this, obj);
return (*this);
}
@@ -545,7 +549,7 @@ public:
{
// Unserialize from this stream
if (!file)
- throw std::ios_base::failure("CAutoFile::operator>>: file handle is NULL");
+ throw std::ios_base::failure("CAutoFile::operator>>: file handle is nullptr");
::Unserialize(*this, obj);
return (*this);
}
@@ -560,10 +564,6 @@ public:
class CBufferedFile
{
private:
- // Disallow copies
- CBufferedFile(const CBufferedFile&);
- CBufferedFile& operator=(const CBufferedFile&);
-
const int nType;
const int nVersion;
@@ -584,11 +584,11 @@ protected:
readNow = nAvail;
if (readNow == 0)
return false;
- size_t read = fread((void*)&vchBuf[pos], 1, readNow, src);
- if (read == 0) {
+ size_t nBytes = fread((void*)&vchBuf[pos], 1, readNow, src);
+ if (nBytes == 0) {
throw std::ios_base::failure(feof(src) ? "CBufferedFile::Fill: end of file" : "CBufferedFile::Fill: fread failed");
} else {
- nSrcPos += read;
+ nSrcPos += nBytes;
return true;
}
}
@@ -605,6 +605,10 @@ public:
fclose();
}
+ // Disallow copies
+ CBufferedFile(const CBufferedFile&) = delete;
+ CBufferedFile& operator=(const CBufferedFile&) = delete;
+
int GetVersion() const { return nVersion; }
int GetType() const { return nType; }
@@ -612,7 +616,7 @@ public:
{
if (src) {
::fclose(src);
- src = NULL;
+ src = nullptr;
}
}
@@ -644,7 +648,7 @@ public:
}
// return the current reading position
- uint64_t GetPos() {
+ uint64_t GetPos() const {
return nReadPos;
}
diff --git a/src/support/allocators/secure.h b/src/support/allocators/secure.h
index 9daba86ef3..39347c73bb 100644
--- a/src/support/allocators/secure.h
+++ b/src/support/allocators/secure.h
@@ -26,13 +26,13 @@ struct secure_allocator : public std::allocator<T> {
typedef typename base::reference reference;
typedef typename base::const_reference const_reference;
typedef typename base::value_type value_type;
- secure_allocator() throw() {}
- secure_allocator(const secure_allocator& a) throw() : base(a) {}
+ secure_allocator() noexcept {}
+ secure_allocator(const secure_allocator& a) noexcept : base(a) {}
template <typename U>
- secure_allocator(const secure_allocator<U>& a) throw() : base(a)
+ secure_allocator(const secure_allocator<U>& a) noexcept : base(a)
{
}
- ~secure_allocator() throw() {}
+ ~secure_allocator() noexcept {}
template <typename _Other>
struct rebind {
typedef secure_allocator<_Other> other;
@@ -45,7 +45,7 @@ struct secure_allocator : public std::allocator<T> {
void deallocate(T* p, std::size_t n)
{
- if (p != NULL) {
+ if (p != nullptr) {
memory_cleanse(p, sizeof(T) * n);
}
LockedPoolManager::Instance().free(p);
diff --git a/src/support/allocators/zeroafterfree.h b/src/support/allocators/zeroafterfree.h
index 28a940ad1b..618874ceee 100644
--- a/src/support/allocators/zeroafterfree.h
+++ b/src/support/allocators/zeroafterfree.h
@@ -22,13 +22,13 @@ struct zero_after_free_allocator : public std::allocator<T> {
typedef typename base::reference reference;
typedef typename base::const_reference const_reference;
typedef typename base::value_type value_type;
- zero_after_free_allocator() throw() {}
- zero_after_free_allocator(const zero_after_free_allocator& a) throw() : base(a) {}
+ zero_after_free_allocator() noexcept {}
+ zero_after_free_allocator(const zero_after_free_allocator& a) noexcept : base(a) {}
template <typename U>
- zero_after_free_allocator(const zero_after_free_allocator<U>& a) throw() : base(a)
+ zero_after_free_allocator(const zero_after_free_allocator<U>& a) noexcept : base(a)
{
}
- ~zero_after_free_allocator() throw() {}
+ ~zero_after_free_allocator() noexcept {}
template <typename _Other>
struct rebind {
typedef zero_after_free_allocator<_Other> other;
@@ -36,7 +36,7 @@ struct zero_after_free_allocator : public std::allocator<T> {
void deallocate(T* p, std::size_t n)
{
- if (p != NULL)
+ if (p != nullptr)
memory_cleanse(p, sizeof(T) * n);
std::allocator<T>::deallocate(p, n);
}
diff --git a/src/support/cleanse.cpp b/src/support/cleanse.cpp
index a2141b2449..95899c9f02 100644
--- a/src/support/cleanse.cpp
+++ b/src/support/cleanse.cpp
@@ -5,9 +5,35 @@
#include "cleanse.h"
-#include <openssl/crypto.h>
+#include <cstring>
+/* Compilers have a bad habit of removing "superfluous" memset calls that
+ * are trying to zero memory. For example, when memset()ing a buffer and
+ * then free()ing it, the compiler might decide that the memset is
+ * unobservable and thus can be removed.
+ *
+ * Previously we used OpenSSL which tried to stop this by a) implementing
+ * memset in assembly on x86 and b) putting the function in its own file
+ * for other platforms.
+ *
+ * This change removes those tricks in favour of using asm directives to
+ * scare the compiler away. As best as our compiler folks can tell, this is
+ * sufficient and will continue to be so.
+ *
+ * Adam Langley <agl@google.com>
+ * Commit: ad1907fe73334d6c696c8539646c21b11178f20f
+ * BoringSSL (LICENSE: ISC)
+ */
void memory_cleanse(void *ptr, size_t len)
{
- OPENSSL_cleanse(ptr, len);
+ std::memset(ptr, 0, len);
+
+ /* As best as we can tell, this is sufficient to break any optimisations that
+ might try to eliminate "superfluous" memsets. If there's an easy way to
+ detect memset_s, it would be better to use that. */
+#if defined(_MSC_VER)
+ __asm;
+#else
+ __asm__ __volatile__("" : : "r"(ptr) : "memory");
+#endif
}
diff --git a/src/support/cleanse.h b/src/support/cleanse.h
index 3e02aa8fd1..f020216c73 100644
--- a/src/support/cleanse.h
+++ b/src/support/cleanse.h
@@ -8,6 +8,7 @@
#include <stdlib.h>
+// Attempt to overwrite data in the specified memory span.
void memory_cleanse(void *ptr, size_t len);
#endif // BITCOIN_SUPPORT_CLEANSE_H
diff --git a/src/support/events.h b/src/support/events.h
index 4f2f3cf9ef..cc6d29aecd 100644
--- a/src/support/events.h
+++ b/src/support/events.h
@@ -27,27 +27,27 @@ MAKE_RAII(evhttp);
MAKE_RAII(evhttp_request);
MAKE_RAII(evhttp_connection);
-raii_event_base obtain_event_base() {
+inline raii_event_base obtain_event_base() {
auto result = raii_event_base(event_base_new());
if (!result.get())
throw std::runtime_error("cannot create event_base");
return result;
}
-raii_event obtain_event(struct event_base* base, evutil_socket_t s, short events, event_callback_fn cb, void* arg) {
+inline raii_event obtain_event(struct event_base* base, evutil_socket_t s, short events, event_callback_fn cb, void* arg) {
return raii_event(event_new(base, s, events, cb, arg));
}
-raii_evhttp obtain_evhttp(struct event_base* base) {
+inline raii_evhttp obtain_evhttp(struct event_base* base) {
return raii_evhttp(evhttp_new(base));
}
-raii_evhttp_request obtain_evhttp_request(void(*cb)(struct evhttp_request *, void *), void *arg) {
+inline raii_evhttp_request obtain_evhttp_request(void(*cb)(struct evhttp_request *, void *), void *arg) {
return raii_evhttp_request(evhttp_request_new(cb, arg));
}
-raii_evhttp_connection obtain_evhttp_connection_base(struct event_base* base, std::string host, uint16_t port) {
- auto result = raii_evhttp_connection(evhttp_connection_base_new(base, NULL, host.c_str(), port));
+inline raii_evhttp_connection obtain_evhttp_connection_base(struct event_base* base, std::string host, uint16_t port) {
+ auto result = raii_evhttp_connection(evhttp_connection_base_new(base, nullptr, host.c_str(), port));
if (!result.get())
throw std::runtime_error("create connection failed");
return result;
diff --git a/src/support/lockedpool.cpp b/src/support/lockedpool.cpp
index 01273c9791..2ead72185f 100644
--- a/src/support/lockedpool.cpp
+++ b/src/support/lockedpool.cpp
@@ -28,7 +28,7 @@
#include <algorithm>
-LockedPoolManager* LockedPoolManager::_instance = NULL;
+LockedPoolManager* LockedPoolManager::_instance = nullptr;
std::once_flag LockedPoolManager::init_flag;
/*******************************************************************************/
@@ -87,7 +87,7 @@ template <class Iterator, class Pair> bool extend(Iterator it, const Pair& other
void Arena::free(void *ptr)
{
- // Freeing the NULL pointer is OK.
+ // Freeing the nullptr pointer is OK.
if (ptr == nullptr) {
return;
}
@@ -148,9 +148,9 @@ class Win32LockedPageAllocator: public LockedPageAllocator
{
public:
Win32LockedPageAllocator();
- void* AllocateLocked(size_t len, bool *lockingSuccess);
- void FreeLocked(void* addr, size_t len);
- size_t GetLimit();
+ void* AllocateLocked(size_t len, bool *lockingSuccess) override;
+ void FreeLocked(void* addr, size_t len) override;
+ size_t GetLimit() override;
private:
size_t page_size;
};
@@ -200,9 +200,9 @@ class PosixLockedPageAllocator: public LockedPageAllocator
{
public:
PosixLockedPageAllocator();
- void* AllocateLocked(size_t len, bool *lockingSuccess);
- void FreeLocked(void* addr, size_t len);
- size_t GetLimit();
+ void* AllocateLocked(size_t len, bool *lockingSuccess) override;
+ void FreeLocked(void* addr, size_t len) override;
+ size_t GetLimit() override;
private:
size_t page_size;
};
@@ -357,8 +357,8 @@ LockedPool::LockedPageArena::~LockedPageArena()
/*******************************************************************************/
// Implementation: LockedPoolManager
//
-LockedPoolManager::LockedPoolManager(std::unique_ptr<LockedPageAllocator> allocator):
- LockedPool(std::move(allocator), &LockedPoolManager::LockingFailed)
+LockedPoolManager::LockedPoolManager(std::unique_ptr<LockedPageAllocator> allocator_in):
+ LockedPool(std::move(allocator_in), &LockedPoolManager::LockingFailed)
{
}
diff --git a/src/support/lockedpool.h b/src/support/lockedpool.h
index f5212bc266..834f0371e2 100644
--- a/src/support/lockedpool.h
+++ b/src/support/lockedpool.h
@@ -50,6 +50,9 @@ public:
Arena(void *base, size_t size, size_t alignment);
virtual ~Arena();
+ Arena(const Arena& other) = delete; // non construction-copyable
+ Arena& operator=(const Arena&) = delete; // non copyable
+
/** Memory statistics. */
struct Stats
{
@@ -85,9 +88,6 @@ public:
*/
bool addressInArena(void *ptr) const { return ptr >= base && ptr < end; }
private:
- Arena(const Arena& other) = delete; // non construction-copyable
- Arena& operator=(const Arena&) = delete; // non copyable
-
/** Map of chunk address to chunk information. This class makes use of the
* sorted order to merge previous and next chunks during deallocation.
*/
@@ -150,9 +150,12 @@ public:
* If this callback is provided and returns false, the allocation fails (hard fail), if
* it returns true the allocation proceeds, but it could warn.
*/
- LockedPool(std::unique_ptr<LockedPageAllocator> allocator, LockingFailed_Callback lf_cb_in = 0);
+ explicit LockedPool(std::unique_ptr<LockedPageAllocator> allocator, LockingFailed_Callback lf_cb_in = nullptr);
~LockedPool();
+ LockedPool(const LockedPool& other) = delete; // non construction-copyable
+ LockedPool& operator=(const LockedPool&) = delete; // non copyable
+
/** Allocate size bytes from this arena.
* Returns pointer on success, or 0 if memory is full or
* the application tried to allocate 0 bytes.
@@ -168,9 +171,6 @@ public:
/** Get pool usage statistics */
Stats stats() const;
private:
- LockedPool(const LockedPool& other) = delete; // non construction-copyable
- LockedPool& operator=(const LockedPool&) = delete; // non copyable
-
std::unique_ptr<LockedPageAllocator> allocator;
/** Create an arena from locked pages */
@@ -217,7 +217,7 @@ public:
}
private:
- LockedPoolManager(std::unique_ptr<LockedPageAllocator> allocator);
+ explicit LockedPoolManager(std::unique_ptr<LockedPageAllocator> allocator);
/** Create a new LockedPoolManager specialized to the OS */
static void CreateInstance();
diff --git a/src/sync.cpp b/src/sync.cpp
index a18d0f1485..87024ccdf2 100644
--- a/src/sync.cpp
+++ b/src/sync.cpp
@@ -9,7 +9,6 @@
#include <stdio.h>
-#include <boost/foreach.hpp>
#include <boost/thread.hpp>
#ifdef DEBUG_LOCKCONTENTION
@@ -46,8 +45,6 @@ struct CLockLocation {
return mutexName + " " + sourceFile + ":" + itostr(sourceLine) + (fTry ? " (TRY)" : "");
}
- std::string MutexName() const { return mutexName; }
-
bool fTry;
private:
std::string mutexName;
@@ -77,78 +74,52 @@ 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) {
+ for (const std::pair<void*, CLockLocation> & i : s2) {
if (i.first == mismatch.first) {
LogPrintf(" (1)");
- 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) {
+ for (const std::pair<void*, CLockLocation> & i : s1) {
if (i.first == mismatch.first) {
LogPrintf(" (1)");
- 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);
+ assert(false);
}
-static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
+static void push_lock(void* c, const CLockLocation& locklocation)
{
- if (lockstack.get() == NULL)
+ if (lockstack.get() == nullptr)
lockstack.reset(new LockStack);
boost::unique_lock<boost::mutex> lock(lockdata.dd_mutex);
(*lockstack).push_back(std::make_pair(c, locklocation));
- if (!fTry) {
- BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, (*lockstack)) {
- if (i.first == c)
- break;
+ for (const std::pair<void*, CLockLocation> & i : (*lockstack)) {
+ if (i.first == c)
+ break;
- std::pair<void*, void*> p1 = std::make_pair(i.first, c);
- if (lockdata.lockorders.count(p1))
- continue;
- lockdata.lockorders[p1] = (*lockstack);
+ std::pair<void*, void*> p1 = std::make_pair(i.first, c);
+ if (lockdata.lockorders.count(p1))
+ continue;
+ lockdata.lockorders[p1] = (*lockstack);
- std::pair<void*, void*> p2 = std::make_pair(c, i.first);
- lockdata.invlockorders.insert(p2);
- if (lockdata.lockorders.count(p2))
- potential_deadlock_detected(p1, lockdata.lockorders[p2], lockdata.lockorders[p1]);
- }
+ std::pair<void*, void*> p2 = std::make_pair(c, i.first);
+ lockdata.invlockorders.insert(p2);
+ if (lockdata.lockorders.count(p2))
+ potential_deadlock_detected(p1, lockdata.lockorders[p2], lockdata.lockorders[p1]);
}
}
@@ -159,7 +130,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), fTry);
+ push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry));
}
void LeaveCritical()
@@ -170,14 +141,14 @@ void LeaveCritical()
std::string LocksHeld()
{
std::string result;
- BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, *lockstack)
+ for (const std::pair<void*, CLockLocation> & i : *lockstack)
result += i.second.ToString() + std::string("\n");
return result;
}
void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs)
{
- BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, *lockstack)
+ for (const std::pair<void*, CLockLocation> & i : *lockstack)
if (i.first == cs)
return;
fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
@@ -191,7 +162,7 @@ void DeleteLock(void* cs)
return;
}
boost::unique_lock<boost::mutex> lock(lockdata.dd_mutex);
- std::pair<void*, void*> item = std::make_pair(cs, (void*)0);
+ std::pair<void*, void*> item = std::make_pair(cs, nullptr);
LockOrders::iterator it = lockdata.lockorders.lower_bound(item);
while (it != lockdata.lockorders.end() && it->first.first == cs) {
std::pair<void*, void*> invitem = std::make_pair(it->first.second, it->first.first);
diff --git a/src/sync.h b/src/sync.h
index 3b29050e0e..0871c5fb4d 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -9,7 +9,6 @@
#include "threadsafety.h"
#include <boost/thread/condition_variable.hpp>
-#include <boost/thread/locks.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/recursive_mutex.hpp>
@@ -97,7 +96,6 @@ public:
}
};
-typedef CCriticalSection CDynamicCriticalSection;
/** Wrapped boost mutex: supports waiting but not recursive locking */
typedef AnnotatedMixin<boost::mutex> CWaitableCriticalSection;
@@ -198,7 +196,7 @@ private:
int value;
public:
- CSemaphore(int init) : value(init) {}
+ explicit CSemaphore(int init) : value(init) {}
void wait()
{
@@ -267,9 +265,9 @@ public:
fHaveGrant = false;
}
- CSemaphoreGrant() : sem(NULL), fHaveGrant(false) {}
+ CSemaphoreGrant() : sem(nullptr), fHaveGrant(false) {}
- CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false)
+ explicit CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false)
{
if (fTry)
TryAcquire();
@@ -282,7 +280,7 @@ public:
Release();
}
- operator bool()
+ operator bool() const
{
return fHaveGrant;
}
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp
index 9345a44fb0..b88ad5ed1b 100644
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -18,12 +18,9 @@
#include <stdint.h>
-#include <boost/assign/list_of.hpp> // for 'map_list_of()'
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
-// Tests this internal-to-main.cpp method:
+// Tests these internal-to-net_processing.cpp methods:
extern bool AddOrphanTx(const CTransactionRef& tx, NodeId peer);
extern void EraseOrphansFor(NodeId peer);
extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans);
@@ -51,26 +48,28 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
connman->ClearBanned();
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
- CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, "", true);
+ CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", true);
dummyNode1.SetSendVersion(PROTOCOL_VERSION);
- GetNodeSignals().InitializeNode(&dummyNode1, *connman);
+ peerLogic->InitializeNode(&dummyNode1);
dummyNode1.nVersion = 1;
+ dummyNode1.fSuccessfullyConnected = true;
Misbehaving(dummyNode1.GetId(), 100); // Should get banned
- SendMessages(&dummyNode1, *connman, interruptDummy);
+ peerLogic->SendMessages(&dummyNode1, interruptDummy);
BOOST_CHECK(connman->IsBanned(addr1));
BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
CAddress addr2(ip(0xa0b0c002), NODE_NONE);
- CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, 1, "", true);
+ CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, 1, CAddress(), "", true);
dummyNode2.SetSendVersion(PROTOCOL_VERSION);
- GetNodeSignals().InitializeNode(&dummyNode2, *connman);
+ peerLogic->InitializeNode(&dummyNode2);
dummyNode2.nVersion = 1;
+ dummyNode2.fSuccessfullyConnected = true;
Misbehaving(dummyNode2.GetId(), 50);
- SendMessages(&dummyNode2, *connman, interruptDummy);
+ peerLogic->SendMessages(&dummyNode2, interruptDummy);
BOOST_CHECK(!connman->IsBanned(addr2)); // 2 not banned yet...
BOOST_CHECK(connman->IsBanned(addr1)); // ... but 1 still should be
Misbehaving(dummyNode2.GetId(), 50);
- SendMessages(&dummyNode2, *connman, interruptDummy);
+ peerLogic->SendMessages(&dummyNode2, interruptDummy);
BOOST_CHECK(connman->IsBanned(addr2));
}
@@ -79,22 +78,23 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
std::atomic<bool> interruptDummy(false);
connman->ClearBanned();
- ForceSetArg("-banscore", "111"); // because 11 is my favorite number
+ gArgs.ForceSetArg("-banscore", "111"); // because 11 is my favorite number
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
- CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, 1, "", true);
+ CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, 1, CAddress(), "", true);
dummyNode1.SetSendVersion(PROTOCOL_VERSION);
- GetNodeSignals().InitializeNode(&dummyNode1, *connman);
+ peerLogic->InitializeNode(&dummyNode1);
dummyNode1.nVersion = 1;
+ dummyNode1.fSuccessfullyConnected = true;
Misbehaving(dummyNode1.GetId(), 100);
- SendMessages(&dummyNode1, *connman, interruptDummy);
+ peerLogic->SendMessages(&dummyNode1, interruptDummy);
BOOST_CHECK(!connman->IsBanned(addr1));
Misbehaving(dummyNode1.GetId(), 10);
- SendMessages(&dummyNode1, *connman, interruptDummy);
+ peerLogic->SendMessages(&dummyNode1, interruptDummy);
BOOST_CHECK(!connman->IsBanned(addr1));
Misbehaving(dummyNode1.GetId(), 1);
- SendMessages(&dummyNode1, *connman, interruptDummy);
+ peerLogic->SendMessages(&dummyNode1, interruptDummy);
BOOST_CHECK(connman->IsBanned(addr1));
- ForceSetArg("-banscore", std::to_string(DEFAULT_BANSCORE_THRESHOLD));
+ gArgs.ForceSetArg("-banscore", std::to_string(DEFAULT_BANSCORE_THRESHOLD));
}
BOOST_AUTO_TEST_CASE(DoS_bantime)
@@ -106,13 +106,14 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
SetMockTime(nStartTime); // Overrides future calls to GetTime()
CAddress addr(ip(0xa0b0c001), NODE_NONE);
- CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, 4, "", true);
+ CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, 4, CAddress(), "", true);
dummyNode.SetSendVersion(PROTOCOL_VERSION);
- GetNodeSignals().InitializeNode(&dummyNode, *connman);
+ peerLogic->InitializeNode(&dummyNode);
dummyNode.nVersion = 1;
+ dummyNode.fSuccessfullyConnected = true;
Misbehaving(dummyNode.GetId(), 100);
- SendMessages(&dummyNode, *connman, interruptDummy);
+ peerLogic->SendMessages(&dummyNode, interruptDummy);
BOOST_CHECK(connman->IsBanned(addr));
SetMockTime(nStartTime+60*60);
@@ -125,7 +126,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
CTransactionRef RandomOrphan()
{
std::map<uint256, COrphanTx>::iterator it;
- it = mapOrphanTransactions.lower_bound(GetRandHash());
+ it = mapOrphanTransactions.lower_bound(InsecureRand256());
if (it == mapOrphanTransactions.end())
it = mapOrphanTransactions.begin();
return it->second.tx;
@@ -144,7 +145,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
CMutableTransaction tx;
tx.vin.resize(1);
tx.vin[0].prevout.n = 0;
- tx.vin[0].prevout.hash = GetRandHash();
+ tx.vin[0].prevout.hash = InsecureRand256();
tx.vin[0].scriptSig << OP_1;
tx.vout.resize(1);
tx.vout[0].nValue = 1*CENT;
diff --git a/src/test/README.md b/src/test/README.md
index 8f99804e10..dbaa9c27f3 100644
--- a/src/test/README.md
+++ b/src/test/README.md
@@ -5,7 +5,10 @@ and tests weren't explicitly disabled.
After configuring, they can be run with `make check`.
-To run the bitcoind tests manually, launch `src/test/test_bitcoin`.
+To run the bitcoind tests manually, launch `src/test/test_bitcoin`. To recompile
+after a test file was modified, run `make` and then run the test again. If you
+modify a non-test file, use `make -C src/test` to recompile only what's needed
+to run the bitcoind tests.
To add more bitcoind tests, add `BOOST_AUTO_TEST_CASE` functions to the existing
.cpp files in the `test/` directory or add new .cpp files that
@@ -50,12 +53,3 @@ examine `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/).
-
-### bitcoin-util-test.py
-
-The test directory also contains the bitcoin-util-test.py tool, which tests bitcoin utils (currently just bitcoin-tx). This test gets run automatically during the `make check` build process. It is also possible to run the test manually from the src directory:
-
-```
-test/bitcoin-util-test.py --srcdir=[current directory]
-
-```
diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp
index 48313915e7..7be29c6d6b 100644
--- a/src/test/addrman_tests.cpp
+++ b/src/test/addrman_tests.cpp
@@ -15,9 +15,14 @@ class CAddrManTest : public CAddrMan
uint64_t state;
public:
- CAddrManTest()
+ explicit CAddrManTest(bool makeDeterministic = true)
{
state = 1;
+
+ if (makeDeterministic) {
+ // Set addrman addr placement to be deterministic.
+ MakeDeterministic();
+ }
}
//! Ensure that bucket placement is always the same for testing purposes.
@@ -27,18 +32,18 @@ public:
insecure_rand = FastRandomContext(true);
}
- int RandomInt(int nMax)
+ int RandomInt(int nMax) override
{
state = (CHashWriter(SER_GETHASH, 0) << state).GetHash().GetCheapHash();
return (unsigned int)(state % nMax);
}
- CAddrInfo* Find(const CNetAddr& addr, int* pnId = NULL)
+ CAddrInfo* Find(const CNetAddr& addr, int* pnId = nullptr)
{
return CAddrMan::Find(addr, pnId);
}
- CAddrInfo* Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId = NULL)
+ CAddrInfo* Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId = nullptr)
{
return CAddrMan::Create(addr, addrSource, pnId);
}
@@ -79,72 +84,77 @@ BOOST_AUTO_TEST_CASE(addrman_simple)
{
CAddrManTest addrman;
- // Set addrman addr placement to be deterministic.
- addrman.MakeDeterministic();
-
CNetAddr source = ResolveIP("252.2.2.2");
- // Test 1: Does Addrman respond correctly when empty.
- BOOST_CHECK(addrman.size() == 0);
+ // Test: Does Addrman respond correctly when empty.
+ BOOST_CHECK_EQUAL(addrman.size(), 0);
CAddrInfo addr_null = addrman.Select();
- BOOST_CHECK(addr_null.ToString() == "[::]:0");
+ BOOST_CHECK_EQUAL(addr_null.ToString(), "[::]:0");
- // Test 2: Does Addrman::Add work as expected.
+ // Test: Does Addrman::Add work as expected.
CService addr1 = ResolveService("250.1.1.1", 8333);
- addrman.Add(CAddress(addr1, NODE_NONE), source);
- BOOST_CHECK(addrman.size() == 1);
+ BOOST_CHECK(addrman.Add(CAddress(addr1, NODE_NONE), source));
+ BOOST_CHECK_EQUAL(addrman.size(), 1);
CAddrInfo addr_ret1 = addrman.Select();
- BOOST_CHECK(addr_ret1.ToString() == "250.1.1.1:8333");
+ BOOST_CHECK_EQUAL(addr_ret1.ToString(), "250.1.1.1:8333");
- // Test 3: Does IP address deduplication work correctly.
+ // Test: Does IP address deduplication work correctly.
// Expected dup IP should not be added.
CService addr1_dup = ResolveService("250.1.1.1", 8333);
- addrman.Add(CAddress(addr1_dup, NODE_NONE), source);
- BOOST_CHECK(addrman.size() == 1);
+ BOOST_CHECK(!addrman.Add(CAddress(addr1_dup, NODE_NONE), source));
+ BOOST_CHECK_EQUAL(addrman.size(), 1);
- // Test 5: New table has one addr and we add a diff addr we should
- // have two addrs.
+ // Test: New table has one addr and we add a diff addr we should
+ // have at least one addr.
+ // Note that addrman's size cannot be tested reliably after insertion, as
+ // hash collisions may occur. But we can always be sure of at least one
+ // success.
+
CService addr2 = ResolveService("250.1.1.2", 8333);
- addrman.Add(CAddress(addr2, NODE_NONE), source);
- BOOST_CHECK(addrman.size() == 2);
+ BOOST_CHECK(addrman.Add(CAddress(addr2, NODE_NONE), source));
+ BOOST_CHECK(addrman.size() >= 1);
- // Test 6: AddrMan::Clear() should empty the new table.
+ // Test: AddrMan::Clear() should empty the new table.
addrman.Clear();
- BOOST_CHECK(addrman.size() == 0);
+ BOOST_CHECK_EQUAL(addrman.size(), 0);
CAddrInfo addr_null2 = addrman.Select();
- BOOST_CHECK(addr_null2.ToString() == "[::]:0");
+ BOOST_CHECK_EQUAL(addr_null2.ToString(), "[::]:0");
+
+ // Test: AddrMan::Add multiple addresses works as expected
+ std::vector<CAddress> vAddr;
+ vAddr.push_back(CAddress(ResolveService("250.1.1.3", 8333), NODE_NONE));
+ vAddr.push_back(CAddress(ResolveService("250.1.1.4", 8333), NODE_NONE));
+ BOOST_CHECK(addrman.Add(vAddr, source));
+ BOOST_CHECK(addrman.size() >= 1);
}
BOOST_AUTO_TEST_CASE(addrman_ports)
{
CAddrManTest addrman;
- // Set addrman addr placement to be deterministic.
- addrman.MakeDeterministic();
-
CNetAddr source = ResolveIP("252.2.2.2");
- BOOST_CHECK(addrman.size() == 0);
+ BOOST_CHECK_EQUAL(addrman.size(), 0);
// Test 7; Addr with same IP but diff port does not replace existing addr.
CService addr1 = ResolveService("250.1.1.1", 8333);
addrman.Add(CAddress(addr1, NODE_NONE), source);
- BOOST_CHECK(addrman.size() == 1);
+ BOOST_CHECK_EQUAL(addrman.size(), 1);
CService addr1_port = ResolveService("250.1.1.1", 8334);
addrman.Add(CAddress(addr1_port, NODE_NONE), source);
- BOOST_CHECK(addrman.size() == 1);
+ BOOST_CHECK_EQUAL(addrman.size(), 1);
CAddrInfo addr_ret2 = addrman.Select();
- BOOST_CHECK(addr_ret2.ToString() == "250.1.1.1:8333");
+ BOOST_CHECK_EQUAL(addr_ret2.ToString(), "250.1.1.1:8333");
- // Test 8: Add same IP but diff port to tried table, it doesn't get added.
+ // Test: Add same IP but diff port to tried table, it doesn't get added.
// Perhaps this is not ideal behavior but it is the current behavior.
addrman.Good(CAddress(addr1_port, NODE_NONE));
- BOOST_CHECK(addrman.size() == 1);
+ BOOST_CHECK_EQUAL(addrman.size(), 1);
bool newOnly = true;
CAddrInfo addr_ret3 = addrman.Select(newOnly);
- BOOST_CHECK(addr_ret3.ToString() == "250.1.1.1:8333");
+ BOOST_CHECK_EQUAL(addr_ret3.ToString(), "250.1.1.1:8333");
}
@@ -152,30 +162,27 @@ BOOST_AUTO_TEST_CASE(addrman_select)
{
CAddrManTest addrman;
- // Set addrman addr placement to be deterministic.
- addrman.MakeDeterministic();
-
CNetAddr source = ResolveIP("252.2.2.2");
- // Test 9: Select from new with 1 addr in new.
+ // Test: Select from new with 1 addr in new.
CService addr1 = ResolveService("250.1.1.1", 8333);
addrman.Add(CAddress(addr1, NODE_NONE), source);
- BOOST_CHECK(addrman.size() == 1);
+ BOOST_CHECK_EQUAL(addrman.size(), 1);
bool newOnly = true;
CAddrInfo addr_ret1 = addrman.Select(newOnly);
- BOOST_CHECK(addr_ret1.ToString() == "250.1.1.1:8333");
+ BOOST_CHECK_EQUAL(addr_ret1.ToString(), "250.1.1.1:8333");
- // Test 10: move addr to tried, select from new expected nothing returned.
+ // Test: move addr to tried, select from new expected nothing returned.
addrman.Good(CAddress(addr1, NODE_NONE));
- BOOST_CHECK(addrman.size() == 1);
+ BOOST_CHECK_EQUAL(addrman.size(), 1);
CAddrInfo addr_ret2 = addrman.Select(newOnly);
- BOOST_CHECK(addr_ret2.ToString() == "[::]:0");
+ BOOST_CHECK_EQUAL(addr_ret2.ToString(), "[::]:0");
CAddrInfo addr_ret3 = addrman.Select();
- BOOST_CHECK(addr_ret3.ToString() == "250.1.1.1:8333");
+ BOOST_CHECK_EQUAL(addr_ret3.ToString(), "250.1.1.1:8333");
- BOOST_CHECK(addrman.size() == 1);
+ BOOST_CHECK_EQUAL(addrman.size(), 1);
// Add three addresses to new table.
@@ -199,83 +206,75 @@ BOOST_AUTO_TEST_CASE(addrman_select)
addrman.Add(CAddress(addr7, NODE_NONE), ResolveService("250.1.1.3", 8333));
addrman.Good(CAddress(addr7, NODE_NONE));
- // Test 11: 6 addrs + 1 addr from last test = 7.
- BOOST_CHECK(addrman.size() == 7);
+ // Test: 6 addrs + 1 addr from last test = 7.
+ BOOST_CHECK_EQUAL(addrman.size(), 7);
- // Test 12: Select pulls from new and tried regardless of port number.
- BOOST_CHECK(addrman.Select().ToString() == "250.4.6.6:8333");
- BOOST_CHECK(addrman.Select().ToString() == "250.3.2.2:9999");
- BOOST_CHECK(addrman.Select().ToString() == "250.3.3.3:9999");
- BOOST_CHECK(addrman.Select().ToString() == "250.4.4.4:8333");
+ // Test: Select pulls from new and tried regardless of port number.
+ std::set<uint16_t> ports;
+ for (int i = 0; i < 20; ++i) {
+ ports.insert(addrman.Select().GetPort());
+ }
+ BOOST_CHECK_EQUAL(ports.size(), 3);
}
BOOST_AUTO_TEST_CASE(addrman_new_collisions)
{
CAddrManTest addrman;
- // Set addrman addr placement to be deterministic.
- addrman.MakeDeterministic();
-
CNetAddr source = ResolveIP("252.2.2.2");
- BOOST_CHECK(addrman.size() == 0);
+ BOOST_CHECK_EQUAL(addrman.size(), 0);
for (unsigned int i = 1; i < 18; i++) {
CService addr = ResolveService("250.1.1." + boost::to_string(i));
addrman.Add(CAddress(addr, NODE_NONE), source);
- //Test 13: No collision in new table yet.
- BOOST_CHECK(addrman.size() == i);
+ //Test: No collision in new table yet.
+ BOOST_CHECK_EQUAL(addrman.size(), i);
}
- //Test 14: new table collision!
+ //Test: new table collision!
CService addr1 = ResolveService("250.1.1.18");
addrman.Add(CAddress(addr1, NODE_NONE), source);
- BOOST_CHECK(addrman.size() == 17);
+ BOOST_CHECK_EQUAL(addrman.size(), 17);
CService addr2 = ResolveService("250.1.1.19");
addrman.Add(CAddress(addr2, NODE_NONE), source);
- BOOST_CHECK(addrman.size() == 18);
+ BOOST_CHECK_EQUAL(addrman.size(), 18);
}
BOOST_AUTO_TEST_CASE(addrman_tried_collisions)
{
CAddrManTest addrman;
- // Set addrman addr placement to be deterministic.
- addrman.MakeDeterministic();
-
CNetAddr source = ResolveIP("252.2.2.2");
- BOOST_CHECK(addrman.size() == 0);
+ BOOST_CHECK_EQUAL(addrman.size(), 0);
for (unsigned int i = 1; i < 80; i++) {
CService addr = ResolveService("250.1.1." + boost::to_string(i));
addrman.Add(CAddress(addr, NODE_NONE), source);
addrman.Good(CAddress(addr, NODE_NONE));
- //Test 15: No collision in tried table yet.
+ //Test: No collision in tried table yet.
BOOST_CHECK_EQUAL(addrman.size(), i);
}
- //Test 16: tried table collision!
+ //Test: tried table collision!
CService addr1 = ResolveService("250.1.1.80");
addrman.Add(CAddress(addr1, NODE_NONE), source);
- BOOST_CHECK(addrman.size() == 79);
+ BOOST_CHECK_EQUAL(addrman.size(), 79);
CService addr2 = ResolveService("250.1.1.81");
addrman.Add(CAddress(addr2, NODE_NONE), source);
- BOOST_CHECK(addrman.size() == 80);
+ BOOST_CHECK_EQUAL(addrman.size(), 80);
}
BOOST_AUTO_TEST_CASE(addrman_find)
{
CAddrManTest addrman;
- // Set addrman addr placement to be deterministic.
- addrman.MakeDeterministic();
-
- BOOST_CHECK(addrman.size() == 0);
+ BOOST_CHECK_EQUAL(addrman.size(), 0);
CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE);
@@ -288,33 +287,27 @@ BOOST_AUTO_TEST_CASE(addrman_find)
addrman.Add(addr2, source2);
addrman.Add(addr3, source1);
- // Test 17: ensure Find returns an IP matching what we searched on.
+ // Test: ensure Find returns an IP matching what we searched on.
CAddrInfo* info1 = addrman.Find(addr1);
- BOOST_CHECK(info1);
- if (info1)
- BOOST_CHECK(info1->ToString() == "250.1.2.1:8333");
+ BOOST_REQUIRE(info1);
+ BOOST_CHECK_EQUAL(info1->ToString(), "250.1.2.1:8333");
// Test 18; Find does not discriminate by port number.
CAddrInfo* info2 = addrman.Find(addr2);
- BOOST_CHECK(info2);
- if (info2)
- BOOST_CHECK(info2->ToString() == info1->ToString());
+ BOOST_REQUIRE(info2);
+ BOOST_CHECK_EQUAL(info2->ToString(), info1->ToString());
- // Test 19: Find returns another IP matching what we searched on.
+ // Test: Find returns another IP matching what we searched on.
CAddrInfo* info3 = addrman.Find(addr3);
- BOOST_CHECK(info3);
- if (info3)
- BOOST_CHECK(info3->ToString() == "251.255.2.1:8333");
+ BOOST_REQUIRE(info3);
+ BOOST_CHECK_EQUAL(info3->ToString(), "251.255.2.1:8333");
}
BOOST_AUTO_TEST_CASE(addrman_create)
{
CAddrManTest addrman;
- // Set addrman addr placement to be deterministic.
- addrman.MakeDeterministic();
-
- BOOST_CHECK(addrman.size() == 0);
+ BOOST_CHECK_EQUAL(addrman.size(), 0);
CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
CNetAddr source1 = ResolveIP("250.1.2.1");
@@ -322,11 +315,11 @@ BOOST_AUTO_TEST_CASE(addrman_create)
int nId;
CAddrInfo* pinfo = addrman.Create(addr1, source1, &nId);
- // Test 20: The result should be the same as the input addr.
- BOOST_CHECK(pinfo->ToString() == "250.1.2.1:8333");
+ // Test: The result should be the same as the input addr.
+ BOOST_CHECK_EQUAL(pinfo->ToString(), "250.1.2.1:8333");
CAddrInfo* info2 = addrman.Find(addr1);
- BOOST_CHECK(info2->ToString() == "250.1.2.1:8333");
+ BOOST_CHECK_EQUAL(info2->ToString(), "250.1.2.1:8333");
}
@@ -334,10 +327,7 @@ BOOST_AUTO_TEST_CASE(addrman_delete)
{
CAddrManTest addrman;
- // Set addrman addr placement to be deterministic.
- addrman.MakeDeterministic();
-
- BOOST_CHECK(addrman.size() == 0);
+ BOOST_CHECK_EQUAL(addrman.size(), 0);
CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
CNetAddr source1 = ResolveIP("250.1.2.1");
@@ -345,26 +335,23 @@ BOOST_AUTO_TEST_CASE(addrman_delete)
int nId;
addrman.Create(addr1, source1, &nId);
- // Test 21: Delete should actually delete the addr.
- BOOST_CHECK(addrman.size() == 1);
+ // Test: Delete should actually delete the addr.
+ BOOST_CHECK_EQUAL(addrman.size(), 1);
addrman.Delete(nId);
- BOOST_CHECK(addrman.size() == 0);
+ BOOST_CHECK_EQUAL(addrman.size(), 0);
CAddrInfo* info2 = addrman.Find(addr1);
- BOOST_CHECK(info2 == NULL);
+ BOOST_CHECK(info2 == nullptr);
}
BOOST_AUTO_TEST_CASE(addrman_getaddr)
{
CAddrManTest addrman;
- // Set addrman addr placement to be deterministic.
- addrman.MakeDeterministic();
-
- // Test 22: Sanity check, GetAddr should never return anything if addrman
+ // Test: Sanity check, GetAddr should never return anything if addrman
// is empty.
- BOOST_CHECK(addrman.size() == 0);
+ BOOST_CHECK_EQUAL(addrman.size(), 0);
std::vector<CAddress> vAddr1 = addrman.GetAddr();
- BOOST_CHECK(vAddr1.size() == 0);
+ BOOST_CHECK_EQUAL(vAddr1.size(), 0);
CAddress addr1 = CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE);
addr1.nTime = GetAdjustedTime(); // Set time so isTerrible = false
@@ -379,7 +366,7 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr)
CNetAddr source1 = ResolveIP("250.1.2.1");
CNetAddr source2 = ResolveIP("250.2.3.3");
- // Test 23: Ensure GetAddr works with new addresses.
+ // Test: Ensure GetAddr works with new addresses.
addrman.Add(addr1, source1);
addrman.Add(addr2, source2);
addrman.Add(addr3, source1);
@@ -387,21 +374,20 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr)
addrman.Add(addr5, source1);
// GetAddr returns 23% of addresses, 23% of 5 is 1 rounded down.
- BOOST_CHECK(addrman.GetAddr().size() == 1);
+ BOOST_CHECK_EQUAL(addrman.GetAddr().size(), 1);
- // Test 24: Ensure GetAddr works with new and tried addresses.
+ // Test: Ensure GetAddr works with new and tried addresses.
addrman.Good(CAddress(addr1, NODE_NONE));
addrman.Good(CAddress(addr2, NODE_NONE));
- BOOST_CHECK(addrman.GetAddr().size() == 1);
+ BOOST_CHECK_EQUAL(addrman.GetAddr().size(), 1);
- // Test 25: Ensure GetAddr still returns 23% when addrman has many addrs.
+ // Test: Ensure GetAddr still returns 23% when addrman has many addrs.
for (unsigned int i = 1; i < (8 * 256); i++) {
int octet1 = i % 256;
- int octet2 = (i / 256) % 256;
- int octet3 = (i / (256 * 2)) % 256;
- std::string strAddr = boost::to_string(octet1) + "." + boost::to_string(octet2) + "." + boost::to_string(octet3) + ".23";
+ int octet2 = i >> 8 % 256;
+ std::string strAddr = boost::to_string(octet1) + "." + boost::to_string(octet2) + ".1.23";
CAddress addr = CAddress(ResolveService(strAddr), NODE_NONE);
-
+
// Ensure that for all addrs in addrman, isTerrible == false.
addr.nTime = GetAdjustedTime();
addrman.Add(addr, ResolveIP(strAddr));
@@ -411,10 +397,10 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr)
std::vector<CAddress> vAddr = addrman.GetAddr();
size_t percent23 = (addrman.size() * 23) / 100;
- BOOST_CHECK(vAddr.size() == percent23);
- BOOST_CHECK(vAddr.size() == 461);
- // (Addrman.size() < number of addresses added) due to address collisons.
- BOOST_CHECK(addrman.size() == 2007);
+ BOOST_CHECK_EQUAL(vAddr.size(), percent23);
+ BOOST_CHECK_EQUAL(vAddr.size(), 461);
+ // (Addrman.size() < number of addresses added) due to address collisions.
+ BOOST_CHECK_EQUAL(addrman.size(), 2006);
}
@@ -422,9 +408,6 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)
{
CAddrManTest addrman;
- // Set addrman addr placement to be deterministic.
- addrman.MakeDeterministic();
-
CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE);
CAddress addr2 = CAddress(ResolveService("250.1.1.1", 9999), NODE_NONE);
@@ -437,13 +420,13 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)
uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
- BOOST_CHECK(info1.GetTriedBucket(nKey1) == 40);
+ BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1), 40);
- // Test 26: Make sure key actually randomizes bucket placement. A fail on
+ // Test: Make sure key actually randomizes bucket placement. A fail on
// this test could be a security issue.
BOOST_CHECK(info1.GetTriedBucket(nKey1) != info1.GetTriedBucket(nKey2));
- // Test 27: Two addresses with same IP but different ports can map to
+ // Test: Two addresses with same IP but different ports can map to
// different buckets because they have different keys.
CAddrInfo info2 = CAddrInfo(addr2, source1);
@@ -458,9 +441,9 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)
int bucket = infoi.GetTriedBucket(nKey1);
buckets.insert(bucket);
}
- // Test 28: IP addresses in the same group (\16 prefix for IPv4) should
+ // Test: IP addresses in the same group (\16 prefix for IPv4) should
// never get more than 8 buckets
- BOOST_CHECK(buckets.size() == 8);
+ BOOST_CHECK_EQUAL(buckets.size(), 8);
buckets.clear();
for (int j = 0; j < 255; j++) {
@@ -470,18 +453,15 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)
int bucket = infoj.GetTriedBucket(nKey1);
buckets.insert(bucket);
}
- // Test 29: IP addresses in the different groups should map to more than
+ // Test: IP addresses in the different groups should map to more than
// 8 buckets.
- BOOST_CHECK(buckets.size() == 160);
+ BOOST_CHECK_EQUAL(buckets.size(), 160);
}
BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
{
CAddrManTest addrman;
- // Set addrman addr placement to be deterministic.
- addrman.MakeDeterministic();
-
CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE);
@@ -492,16 +472,18 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();
uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
- BOOST_CHECK(info1.GetNewBucket(nKey1) == 786);
+ // Test: Make sure the buckets are what we expect
+ BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1), 786);
+ BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1), 786);
- // Test 30: Make sure key actually randomizes bucket placement. A fail on
+ // Test: Make sure key actually randomizes bucket placement. A fail on
// this test could be a security issue.
BOOST_CHECK(info1.GetNewBucket(nKey1) != info1.GetNewBucket(nKey2));
- // Test 31: Ports should not effect bucket placement in the addr
+ // Test: Ports should not effect bucket placement in the addr
CAddrInfo info2 = CAddrInfo(addr2, source1);
BOOST_CHECK(info1.GetKey() != info2.GetKey());
- BOOST_CHECK(info1.GetNewBucket(nKey1) == info2.GetNewBucket(nKey1));
+ BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1), info2.GetNewBucket(nKey1));
std::set<int> buckets;
for (int i = 0; i < 255; i++) {
@@ -511,9 +493,9 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
int bucket = infoi.GetNewBucket(nKey1);
buckets.insert(bucket);
}
- // Test 32: IP addresses in the same group (\16 prefix for IPv4) should
+ // Test: IP addresses in the same group (\16 prefix for IPv4) should
// always map to the same bucket.
- BOOST_CHECK(buckets.size() == 1);
+ BOOST_CHECK_EQUAL(buckets.size(), 1);
buckets.clear();
for (int j = 0; j < 4 * 255; j++) {
@@ -524,7 +506,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
int bucket = infoj.GetNewBucket(nKey1);
buckets.insert(bucket);
}
- // Test 33: IP addresses in the same source groups should map to no more
+ // Test: IP addresses in the same source groups should map to no more
// than 64 buckets.
BOOST_CHECK(buckets.size() <= 64);
@@ -536,7 +518,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
int bucket = infoj.GetNewBucket(nKey1);
buckets.insert(bucket);
}
- // Test 34: IP addresses in the different source groups should map to more
+ // Test: IP addresses in the different source groups should map to more
// than 64 buckets.
BOOST_CHECK(buckets.size() > 64);
}
diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp
index 3f15a0dec1..4a533b5bf2 100644
--- a/src/test/allocator_tests.cpp
+++ b/src/test/allocator_tests.cpp
@@ -131,7 +131,7 @@ class TestLockedPageAllocator: public LockedPageAllocator
{
public:
TestLockedPageAllocator(int count_in, int lockedcount_in): count(count_in), lockedcount(lockedcount_in) {}
- void* AllocateLocked(size_t len, bool *lockingSuccess)
+ void* AllocateLocked(size_t len, bool *lockingSuccess) override
{
*lockingSuccess = false;
if (count > 0) {
@@ -146,10 +146,10 @@ public:
}
return 0;
}
- void FreeLocked(void* addr, size_t len)
+ void FreeLocked(void* addr, size_t len) override
{
}
- size_t GetLimit()
+ size_t GetLimit() override
{
return std::numeric_limits<size_t>::max();
}
diff --git a/src/test/amount_tests.cpp b/src/test/amount_tests.cpp
index fd6f88b366..952cf901f0 100644
--- a/src/test/amount_tests.cpp
+++ b/src/test/amount_tests.cpp
@@ -3,15 +3,23 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "amount.h"
+#include "policy/feerate.h"
#include "test/test_bitcoin.h"
#include <boost/test/unit_test.hpp>
BOOST_FIXTURE_TEST_SUITE(amount_tests, BasicTestingSetup)
+BOOST_AUTO_TEST_CASE(MoneyRangeTest)
+{
+ BOOST_CHECK_EQUAL(MoneyRange(CAmount(-1)), false);
+ BOOST_CHECK_EQUAL(MoneyRange(MAX_MONEY + CAmount(1)), false);
+ BOOST_CHECK_EQUAL(MoneyRange(CAmount(1)), true);
+}
+
BOOST_AUTO_TEST_CASE(GetFeeTest)
{
- CFeeRate feeRate;
+ CFeeRate feeRate, altFeeRate;
feeRate = CFeeRate(0);
// Must always return 0
@@ -53,6 +61,11 @@ BOOST_AUTO_TEST_CASE(GetFeeTest)
BOOST_CHECK_EQUAL(feeRate.GetFee(8), -1); // Special case: returns -1 instead of 0
BOOST_CHECK_EQUAL(feeRate.GetFee(9), -1);
+ // check alternate constructor
+ feeRate = CFeeRate(1000);
+ altFeeRate = CFeeRate(feeRate);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(100), altFeeRate.GetFee(100));
+
// Check full constructor
// default value
BOOST_CHECK(CFeeRate(CAmount(-1), 1000) == CFeeRate(-1));
@@ -68,4 +81,28 @@ BOOST_AUTO_TEST_CASE(GetFeeTest)
CFeeRate(MAX_MONEY, std::numeric_limits<size_t>::max() >> 1).GetFeePerK();
}
+BOOST_AUTO_TEST_CASE(BinaryOperatorTest)
+{
+ CFeeRate a, b;
+ a = CFeeRate(1);
+ b = CFeeRate(2);
+ BOOST_CHECK(a < b);
+ BOOST_CHECK(b > a);
+ BOOST_CHECK(a == a);
+ BOOST_CHECK(a <= b);
+ BOOST_CHECK(a <= a);
+ BOOST_CHECK(b >= a);
+ BOOST_CHECK(b >= b);
+ // a should be 0.00000002 BTC/kB now
+ a += a;
+ BOOST_CHECK(a == b);
+}
+
+BOOST_AUTO_TEST_CASE(ToStringTest)
+{
+ CFeeRate feeRate;
+ feeRate = CFeeRate(1);
+ BOOST_CHECK_EQUAL(feeRate.ToString(), "0.00000001 BTC/kB");
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/arith_uint256_tests.cpp b/src/test/arith_uint256_tests.cpp
index 45ae7d4636..2c98fbcfd6 100644
--- a/src/test/arith_uint256_tests.cpp
+++ b/src/test/arith_uint256_tests.cpp
@@ -219,7 +219,7 @@ BOOST_AUTO_TEST_CASE( unaryOperators ) // ! ~ -
// Check if doing _A_ _OP_ _B_ results in the same as applying _OP_ onto each
-// element of Aarray and Barray, and then converting the result into a arith_uint256.
+// element of Aarray and Barray, and then converting the result into an arith_uint256.
#define CHECKBITWISEOPERATOR(_A_,_B_,_OP_) \
for (unsigned int i = 0; i < 32; ++i) { TmpArray[i] = _A_##Array[i] _OP_ _B_##Array[i]; } \
BOOST_CHECK(arith_uint256V(std::vector<unsigned char>(TmpArray,TmpArray+32)) == (_A_##L _OP_ _B_##L));
diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp
index 6cd998990b..6bc6dd5187 100644
--- a/src/test/base58_tests.cpp
+++ b/src/test/base58_tests.cpp
@@ -10,15 +10,15 @@
#include "key.h"
#include "script/script.h"
+#include "test/test_bitcoin.h"
#include "uint256.h"
#include "util.h"
#include "utilstrencodings.h"
-#include "test/test_bitcoin.h"
-#include <boost/foreach.hpp>
+#include <univalue.h>
+
#include <boost/test/unit_test.hpp>
-#include <univalue.h>
extern UniValue read_json(const std::string& jsondata);
@@ -73,63 +73,18 @@ BOOST_AUTO_TEST_CASE(base58_DecodeBase58)
BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end());
}
-// Visitor to check address type
-class TestAddrTypeVisitor : public boost::static_visitor<bool>
-{
-private:
- std::string exp_addrType;
-public:
- TestAddrTypeVisitor(const std::string &_exp_addrType) : exp_addrType(_exp_addrType) { }
- bool operator()(const CKeyID &id) const
- {
- return (exp_addrType == "pubkey");
- }
- bool operator()(const CScriptID &id) const
- {
- return (exp_addrType == "script");
- }
- bool operator()(const CNoDestination &no) const
- {
- return (exp_addrType == "none");
- }
-};
-
-// Visitor to check address payload
-class TestPayloadVisitor : public boost::static_visitor<bool>
-{
-private:
- std::vector<unsigned char> exp_payload;
-public:
- TestPayloadVisitor(std::vector<unsigned char> &_exp_payload) : exp_payload(_exp_payload) { }
- bool operator()(const CKeyID &id) const
- {
- uint160 exp_key(exp_payload);
- return exp_key == id;
- }
- bool operator()(const CScriptID &id) const
- {
- uint160 exp_key(exp_payload);
- return exp_key == id;
- }
- bool operator()(const CNoDestination &no) const
- {
- return exp_payload.size() == 0;
- }
-};
-
// Goal: check that parsed keys match test payload
BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
{
UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
CBitcoinSecret secret;
- CBitcoinAddress addr;
+ CTxDestination destination;
SelectParams(CBaseChainParams::MAIN);
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)
- {
+ if (test.size() < 3) { // Allow for extra stuff (useful for comments)
BOOST_ERROR("Bad test: " << strTest);
continue;
}
@@ -137,16 +92,11 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());
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)
- SelectParams(CBaseChainParams::TESTNET);
- else
- SelectParams(CBaseChainParams::MAIN);
- if(isPrivkey)
- {
+ SelectParams(find_value(metadata, "chain").get_str());
+ bool try_case_flip = find_value(metadata, "tryCaseFlip").isNull() ? false : find_value(metadata, "tryCaseFlip").get_bool();
+ if (isPrivkey) {
bool isCompressed = find_value(metadata, "isCompressed").get_bool();
// Must be valid private key
- // Note: CBitcoinSecret::SetString tests isValid, whereas CBitcoinAddress does not!
BOOST_CHECK_MESSAGE(secret.SetString(exp_base58string), "!SetString:"+ strTest);
BOOST_CHECK_MESSAGE(secret.IsValid(), "!IsValid:" + strTest);
CKey privkey = secret.GetKey();
@@ -154,18 +104,29 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), "key mismatch:" + strTest);
// Private key must be invalid public key
- addr.SetString(exp_base58string);
- BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid privkey as pubkey:" + strTest);
- }
- else
- {
- std::string exp_addrType = find_value(metadata, "addrType").get_str(); // "script" or "pubkey"
+ destination = DecodeDestination(exp_base58string);
+ BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid privkey as pubkey:" + strTest);
+ } else {
// Must be valid public key
- BOOST_CHECK_MESSAGE(addr.SetString(exp_base58string), "SetString:" + strTest);
- BOOST_CHECK_MESSAGE(addr.IsValid(), "!IsValid:" + strTest);
- BOOST_CHECK_MESSAGE(addr.IsScript() == (exp_addrType == "script"), "isScript mismatch" + strTest);
- CTxDestination dest = addr.Get();
- BOOST_CHECK_MESSAGE(boost::apply_visitor(TestAddrTypeVisitor(exp_addrType), dest), "addrType mismatch" + strTest);
+ destination = DecodeDestination(exp_base58string);
+ CScript script = GetScriptForDestination(destination);
+ BOOST_CHECK_MESSAGE(IsValidDestination(destination), "!IsValid:" + strTest);
+ BOOST_CHECK_EQUAL(HexStr(script), HexStr(exp_payload));
+
+ // Try flipped case version
+ for (char& c : exp_base58string) {
+ if (c >= 'a' && c <= 'z') {
+ c = (c - 'a') + 'A';
+ } else if (c >= 'A' && c <= 'Z') {
+ c = (c - 'A') + 'a';
+ }
+ }
+ destination = DecodeDestination(exp_base58string);
+ BOOST_CHECK_MESSAGE(IsValidDestination(destination) == try_case_flip, "!IsValid case flipped:" + strTest);
+ if (IsValidDestination(destination)) {
+ script = GetScriptForDestination(destination);
+ BOOST_CHECK_EQUAL(HexStr(script), HexStr(exp_payload));
+ }
// Public key must be invalid private key
secret.SetString(exp_base58string);
@@ -191,13 +152,8 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());
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)
- SelectParams(CBaseChainParams::TESTNET);
- else
- SelectParams(CBaseChainParams::MAIN);
- if(isPrivkey)
- {
+ SelectParams(find_value(metadata, "chain").get_str());
+ if (isPrivkey) {
bool isCompressed = find_value(metadata, "isCompressed").get_bool();
CKey key;
key.Set(exp_payload.begin(), exp_payload.end(), isCompressed);
@@ -205,48 +161,26 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
CBitcoinSecret secret;
secret.SetKey(key);
BOOST_CHECK_MESSAGE(secret.ToString() == exp_base58string, "result mismatch: " + strTest);
- }
- else
- {
- std::string exp_addrType = find_value(metadata, "addrType").get_str();
+ } else {
CTxDestination dest;
- if(exp_addrType == "pubkey")
- {
- dest = CKeyID(uint160(exp_payload));
- }
- else if(exp_addrType == "script")
- {
- dest = CScriptID(uint160(exp_payload));
- }
- else if(exp_addrType == "none")
- {
- dest = CNoDestination();
- }
- else
- {
- BOOST_ERROR("Bad addrtype: " << strTest);
- continue;
- }
- CBitcoinAddress addrOut;
- BOOST_CHECK_MESSAGE(addrOut.Set(dest), "encode dest: " + strTest);
- BOOST_CHECK_MESSAGE(addrOut.ToString() == exp_base58string, "mismatch: " + strTest);
+ CScript exp_script(exp_payload.begin(), exp_payload.end());
+ ExtractDestination(exp_script, dest);
+ std::string address = EncodeDestination(dest);
+
+ BOOST_CHECK_EQUAL(address, exp_base58string);
}
}
- // Visiting a CNoDestination must fail
- CBitcoinAddress dummyAddr;
- CTxDestination nodest = CNoDestination();
- BOOST_CHECK(!dummyAddr.Set(nodest));
-
SelectParams(CBaseChainParams::MAIN);
}
+
// Goal: check that base58 parsing code is robust against a variety of corrupted data
BOOST_AUTO_TEST_CASE(base58_keys_invalid)
{
UniValue tests = read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); // Negative testcases
CBitcoinSecret secret;
- CBitcoinAddress addr;
+ CTxDestination destination;
for (unsigned int idx = 0; idx < tests.size(); idx++) {
UniValue test = tests[idx];
@@ -259,13 +193,15 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid)
std::string exp_base58string = test[0].get_str();
// must be invalid as public and as private key
- addr.SetString(exp_base58string);
- BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid pubkey:" + strTest);
- secret.SetString(exp_base58string);
- BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid privkey:" + strTest);
+ for (auto chain : { CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::REGTEST }) {
+ SelectParams(chain);
+ destination = DecodeDestination(exp_base58string);
+ BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid pubkey in mainnet:" + strTest);
+ secret.SetString(exp_base58string);
+ BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid privkey in mainnet:" + strTest);
+ }
}
}
BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/src/test/bctest.py b/src/test/bctest.py
deleted file mode 100644
index adc5d0e418..0000000000
--- a/src/test/bctest.py
+++ /dev/null
@@ -1,121 +0,0 @@
-# Copyright 2014 BitPay Inc.
-# Copyright 2016 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-from __future__ import division,print_function,unicode_literals
-import subprocess
-import os
-import json
-import sys
-import binascii
-import difflib
-import logging
-
-def parse_output(a, fmt):
- """Parse the output according to specified format.
-
- Raise an error if the output can't be parsed."""
- if fmt == 'json': # json: compare parsed data
- return json.loads(a)
- elif fmt == 'hex': # hex: parse and compare binary data
- return binascii.a2b_hex(a.strip())
- else:
- raise NotImplementedError("Don't know how to compare %s" % fmt)
-
-def bctest(testDir, testObj, exeext):
- """Runs a single test, comparing output and RC to expected output and RC.
-
- Raises an error if input can't be read, executable fails, or output/RC
- are not as expected. Error is caught by bctester() and reported.
- """
- # Get the exec names and arguments
- execprog = testObj['exec'] + exeext
- execargs = testObj['args']
- execrun = [execprog] + execargs
-
- # Read the input data (if there is any)
- stdinCfg = None
- inputData = None
- if "input" in testObj:
- filename = testDir + "/" + testObj['input']
- inputData = open(filename).read()
- stdinCfg = subprocess.PIPE
-
- # Read the expected output data (if there is any)
- outputFn = None
- outputData = None
- if "output_cmp" in testObj:
- outputFn = testObj['output_cmp']
- outputType = os.path.splitext(outputFn)[1][1:] # output type from file extension (determines how to compare)
- try:
- outputData = open(testDir + "/" + outputFn).read()
- except:
- logging.error("Output file " + outputFn + " can not be opened")
- raise
- if not outputData:
- logging.error("Output data missing for " + outputFn)
- raise Exception
-
- # Run the test
- proc = subprocess.Popen(execrun, stdin=stdinCfg, stdout=subprocess.PIPE, stderr=subprocess.PIPE,universal_newlines=True)
- try:
- outs = proc.communicate(input=inputData)
- except OSError:
- logging.error("OSError, Failed to execute " + execprog)
- raise
-
- if outputData:
- # Parse command output and expected output
- try:
- a_parsed = parse_output(outs[0], outputType)
- except Exception as e:
- logging.error('Error parsing command output as %s: %s' % (outputType,e))
- raise
- try:
- b_parsed = parse_output(outputData, outputType)
- except Exception as e:
- logging.error('Error parsing expected output %s as %s: %s' % (outputFn,outputType,e))
- raise
- # Compare data
- if a_parsed != b_parsed:
- logging.error("Output data mismatch for " + outputFn + " (format " + outputType + ")")
- raise Exception
- # Compare formatting
- if outs[0] != outputData:
- error_message = "Output formatting mismatch for " + outputFn + ":\n"
- error_message += "".join(difflib.context_diff(outputData.splitlines(True),
- outs[0].splitlines(True),
- fromfile=outputFn,
- tofile="returned"))
- logging.error(error_message)
- raise Exception
-
- # Compare the return code to the expected return code
- wantRC = 0
- if "return_code" in testObj:
- wantRC = testObj['return_code']
- if proc.returncode != wantRC:
- logging.error("Return code mismatch for " + outputFn)
- raise Exception
-
-def bctester(testDir, input_basename, buildenv):
- """ Loads and parses the input file, runs all tests and reports results"""
- input_filename = testDir + "/" + input_basename
- raw_data = open(input_filename).read()
- input_data = json.loads(raw_data)
-
- failed_testcases = []
-
- for testObj in input_data:
- try:
- bctest(testDir, testObj, buildenv.exeext)
- logging.info("PASSED: " + testObj["description"])
- except:
- logging.info("FAILED: " + testObj["description"])
- failed_testcases.append(testObj["description"])
-
- if failed_testcases:
- logging.error("FAILED TESTCASES: [" + ", ".join(failed_testcases) + "]")
- sys.exit(1)
- else:
- sys.exit(0)
diff --git a/src/test/bech32_tests.cpp b/src/test/bech32_tests.cpp
new file mode 100644
index 0000000000..ce4cddd64b
--- /dev/null
+++ b/src/test/bech32_tests.cpp
@@ -0,0 +1,67 @@
+// Copyright (c) 2017 Pieter Wuille
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "bech32.h"
+#include "test/test_bitcoin.h"
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_FIXTURE_TEST_SUITE(bech32_tests, BasicTestingSetup)
+
+bool CaseInsensitiveEqual(const std::string &s1, const std::string &s2)
+{
+ if (s1.size() != s2.size()) return false;
+ for (size_t i = 0; i < s1.size(); ++i) {
+ char c1 = s1[i];
+ if (c1 >= 'A' && c1 <= 'Z') c1 -= ('A' - 'a');
+ char c2 = s2[i];
+ if (c2 >= 'A' && c2 <= 'Z') c2 -= ('A' - 'a');
+ if (c1 != c2) return false;
+ }
+ return true;
+}
+
+BOOST_AUTO_TEST_CASE(bip173_testvectors_valid)
+{
+ static const std::string CASES[] = {
+ "A12UEL5L",
+ "a12uel5l",
+ "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs",
+ "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
+ "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j",
+ "split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w",
+ "?1ezyfcl",
+ };
+ for (const std::string& str : CASES) {
+ auto ret = bech32::Decode(str);
+ BOOST_CHECK(!ret.first.empty());
+ std::string recode = bech32::Encode(ret.first, ret.second);
+ BOOST_CHECK(!recode.empty());
+ BOOST_CHECK(CaseInsensitiveEqual(str, recode));
+ }
+}
+
+BOOST_AUTO_TEST_CASE(bip173_testvectors_invalid)
+{
+ static const std::string CASES[] = {
+ " 1nwldj5",
+ "\x7f""1axkwrx",
+ "\x80""1eym55h",
+ "an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx",
+ "pzry9x0s0muk",
+ "1pzry9x0s0muk",
+ "x1b4n0q5v",
+ "li1dgmt3",
+ "de1lg7wt\xff",
+ "A1G7SGD8",
+ "10a06t8",
+ "1qzzfhee",
+ };
+ for (const std::string& str : CASES) {
+ auto ret = bech32::Decode(str);
+ BOOST_CHECK(ret.first.empty());
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp
index 7f1c2a32dd..e123c26ad0 100644
--- a/src/test/bip32_tests.cpp
+++ b/src/test/bip32_tests.cpp
@@ -24,7 +24,7 @@ struct TestVector {
std::string strHexMaster;
std::vector<TestDerivation> vDerive;
- TestVector(std::string strHexMasterIn) : strHexMaster(strHexMasterIn) {}
+ explicit TestVector(std::string strHexMasterIn) : strHexMaster(strHexMasterIn) {}
TestVector& operator()(std::string pub, std::string prv, unsigned int nChild) {
vDerive.push_back(TestDerivation());
@@ -78,13 +78,22 @@ TestVector test2 =
"xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j",
0);
+TestVector test3 =
+ TestVector("4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be")
+ ("xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13",
+ "xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6",
+ 0x80000000)
+ ("xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y",
+ "xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L",
+ 0);
+
void RunTest(const TestVector &test) {
std::vector<unsigned char> seed = ParseHex(test.strHexMaster);
CExtKey key;
CExtPubKey pubkey;
- key.SetMaster(&seed[0], seed.size());
+ key.SetMaster(seed.data(), seed.size());
pubkey = key.Neuter();
- BOOST_FOREACH(const TestDerivation &derive, test.vDerive) {
+ for (const TestDerivation &derive : test.vDerive) {
unsigned char data[74];
key.Encode(data);
pubkey.Encode(data);
@@ -146,4 +155,8 @@ BOOST_AUTO_TEST_CASE(bip32_test2) {
RunTest(test2);
}
+BOOST_AUTO_TEST_CASE(bip32_test3) {
+ RunTest(test3);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/bitcoin-util-test.py b/src/test/bitcoin-util-test.py
deleted file mode 100755
index 1c090b3f3f..0000000000
--- a/src/test/bitcoin-util-test.py
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2014 BitPay Inc.
-# Copyright 2016 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-from __future__ import division,print_function,unicode_literals
-import os
-import sys
-import bctest
-import buildenv
-import argparse
-import logging
-
-help_text="""Test framework for bitcoin utils.
-
-Runs automatically during `make check`.
-
-Can also be run manually from the src directory by specifying the source directory:
-
-test/bitcoin-util-test.py --srcdir='srcdir' [--verbose]
-"""
-
-if __name__ == '__main__':
- # Try to get the source directory from the environment variables. This will
- # be set for `make check` automated runs. If environment variable is not set,
- # then get the source directory from command line args.
- try:
- srcdir = os.environ["srcdir"]
- verbose = False
- except:
- parser = argparse.ArgumentParser(description=help_text)
- parser.add_argument('-s', '--srcdir')
- parser.add_argument('-v', '--verbose', action='store_true')
- args = parser.parse_args()
- srcdir = args.srcdir
- verbose = args.verbose
-
- if verbose:
- level = logging.DEBUG
- else:
- level = logging.ERROR
- formatter = '%(asctime)s - %(levelname)s - %(message)s'
- # Add the format/level to the logger
- logging.basicConfig(format = formatter, level=level)
-
- bctest.bctester(srcdir + "/test/data", "bitcoin-util-test.json", buildenv)
diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp
index e3876e9695..f2d5b385d0 100644
--- a/src/test/blockencodings_tests.cpp
+++ b/src/test/blockencodings_tests.cpp
@@ -11,6 +11,8 @@
#include <boost/test/unit_test.hpp>
+std::vector<std::pair<uint256, CTransactionRef>> extra_txn;
+
struct RegtestingSetup : public TestingSetup {
RegtestingSetup() : TestingSetup(CBaseChainParams::REGTEST) {}
};
@@ -28,16 +30,16 @@ static CBlock BuildBlockTestCase() {
block.vtx.resize(3);
block.vtx[0] = MakeTransactionRef(tx);
block.nVersion = 42;
- block.hashPrevBlock = GetRandHash();
+ block.hashPrevBlock = InsecureRand256();
block.nBits = 0x207fffff;
- tx.vin[0].prevout.hash = GetRandHash();
+ tx.vin[0].prevout.hash = InsecureRand256();
tx.vin[0].prevout.n = 0;
block.vtx[1] = MakeTransactionRef(tx);
tx.vin.resize(10);
for (size_t i = 0; i < tx.vin.size(); i++) {
- tx.vin[i].prevout.hash = GetRandHash();
+ tx.vin[i].prevout.hash = InsecureRand256();
tx.vin[i].prevout.n = 0;
}
block.vtx[2] = MakeTransactionRef(tx);
@@ -49,13 +51,13 @@ static CBlock BuildBlockTestCase() {
return block;
}
-// Number of shared use_counts we expect for a tx we havent touched
+// Number of shared use_counts we expect for a tx we haven't touched
// == 2 (mempool + our copy from the GetSharedTx call)
#define SHARED_TX_OFFSET 2
BOOST_AUTO_TEST_CASE(SimpleRoundTripTest)
{
- CTxMemPool pool(CFeeRate(0));
+ CTxMemPool pool;
TestMemPoolEntryHelper entry;
CBlock block(BuildBlockTestCase());
@@ -73,7 +75,7 @@ BOOST_AUTO_TEST_CASE(SimpleRoundTripTest)
stream >> shortIDs2;
PartiallyDownloadedBlock partialBlock(&pool);
- BOOST_CHECK(partialBlock.InitData(shortIDs2) == READ_STATUS_OK);
+ BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK);
BOOST_CHECK( partialBlock.IsTxAvailable(0));
BOOST_CHECK(!partialBlock.IsTxAvailable(1));
BOOST_CHECK( partialBlock.IsTxAvailable(2));
@@ -116,12 +118,12 @@ public:
std::vector<uint64_t> shorttxids;
std::vector<PrefilledTransaction> prefilledtxn;
- TestHeaderAndShortIDs(const CBlockHeaderAndShortTxIDs& orig) {
+ explicit TestHeaderAndShortIDs(const CBlockHeaderAndShortTxIDs& orig) {
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << orig;
stream >> *this;
}
- TestHeaderAndShortIDs(const CBlock& block) :
+ explicit TestHeaderAndShortIDs(const CBlock& block) :
TestHeaderAndShortIDs(CBlockHeaderAndShortTxIDs(block, true)) {}
uint64_t GetShortID(const uint256& txhash) const {
@@ -154,7 +156,7 @@ public:
BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
{
- CTxMemPool pool(CFeeRate(0));
+ CTxMemPool pool;
TestMemPoolEntryHelper entry;
CBlock block(BuildBlockTestCase());
@@ -179,7 +181,7 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
stream >> shortIDs2;
PartiallyDownloadedBlock partialBlock(&pool);
- BOOST_CHECK(partialBlock.InitData(shortIDs2) == READ_STATUS_OK);
+ BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK);
BOOST_CHECK(!partialBlock.IsTxAvailable(0));
BOOST_CHECK( partialBlock.IsTxAvailable(1));
BOOST_CHECK( partialBlock.IsTxAvailable(2));
@@ -220,7 +222,7 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
{
- CTxMemPool pool(CFeeRate(0));
+ CTxMemPool pool;
TestMemPoolEntryHelper entry;
CBlock block(BuildBlockTestCase());
@@ -245,7 +247,7 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
stream >> shortIDs2;
PartiallyDownloadedBlock partialBlock(&pool);
- BOOST_CHECK(partialBlock.InitData(shortIDs2) == READ_STATUS_OK);
+ BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK);
BOOST_CHECK( partialBlock.IsTxAvailable(0));
BOOST_CHECK( partialBlock.IsTxAvailable(1));
BOOST_CHECK( partialBlock.IsTxAvailable(2));
@@ -270,7 +272,7 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
{
- CTxMemPool pool(CFeeRate(0));
+ CTxMemPool pool;
CMutableTransaction coinbase;
coinbase.vin.resize(1);
coinbase.vin[0].scriptSig.resize(10);
@@ -281,7 +283,7 @@ BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
block.vtx.resize(1);
block.vtx[0] = MakeTransactionRef(std::move(coinbase));
block.nVersion = 42;
- block.hashPrevBlock = GetRandHash();
+ block.hashPrevBlock = InsecureRand256();
block.nBits = 0x207fffff;
bool mutated;
@@ -300,7 +302,7 @@ BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
stream >> shortIDs2;
PartiallyDownloadedBlock partialBlock(&pool);
- BOOST_CHECK(partialBlock.InitData(shortIDs2) == READ_STATUS_OK);
+ BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK);
BOOST_CHECK(partialBlock.IsTxAvailable(0));
CBlock block2;
@@ -314,7 +316,7 @@ BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
BOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest) {
BlockTransactionsRequest req1;
- req1.blockhash = GetRandHash();
+ req1.blockhash = InsecureRand256();
req1.indexes.resize(4);
req1.indexes[0] = 0;
req1.indexes[1] = 1;
diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp
index 27bc92d670..eac2c102a6 100644
--- a/src/test/bloom_tests.cpp
+++ b/src/test/bloom_tests.cpp
@@ -8,6 +8,7 @@
#include "clientversion.h"
#include "key.h"
#include "merkleblock.h"
+#include "primitives/block.h"
#include "random.h"
#include "serialize.h"
#include "streams.h"
@@ -19,7 +20,6 @@
#include <vector>
#include <boost/test/unit_test.hpp>
-#include <boost/tuple/tuple.hpp>
BOOST_FIXTURE_TEST_SUITE(bloom_tests, BasicTestingSetup)
@@ -155,8 +155,8 @@ BOOST_AUTO_TEST_CASE(bloom_match)
COutPoint prevOutPoint(uint256S("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0);
{
std::vector<unsigned char> data(32 + sizeof(unsigned int));
- memcpy(&data[0], prevOutPoint.hash.begin(), 32);
- memcpy(&data[32], &prevOutPoint.n, sizeof(unsigned int));
+ memcpy(data.data(), prevOutPoint.hash.begin(), 32);
+ memcpy(data.data()+32, &prevOutPoint.n, sizeof(unsigned int));
filter.insert(data);
}
BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match manually serialized COutPoint");
@@ -180,20 +180,15 @@ BOOST_AUTO_TEST_CASE(bloom_match)
BOOST_AUTO_TEST_CASE(merkle_block_1)
{
- // Random real block (0000000000013b8ab2cd513b0261a14096412195a72a0c4827d229dcc7e0f7af)
- // With 9 txes
- CBlock block;
- CDataStream stream(ParseHex("0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb6800000000000005275289558f51c9966699404ae2294730c3c9f9bda53523ce50e9b95e558da2fdb261b4d4c86041b1ab1bf930901000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0146ffffffff0100f2052a01000000434104e18f7afbe4721580e81e8414fc8c24d7cfacf254bb5c7b949450c3e997c2dc1242487a8169507b631eb3771f2b425483fb13102c4eb5d858eef260fe70fbfae0ac00000000010000000196608ccbafa16abada902780da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100dab24889213caf43ae6adc41cf1c9396c08240c199f5225acf45416330fd7dbd022100fe37900e0644bf574493a07fc5edba06dbc07c311b947520c2d514bc5725dcb401ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369ed2fc393ce288ac000000000100000001fb766c1288458c2bafcfec81e48b24d98ec706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268ba165ce0ad2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21adc6c401887f2bfd1922f11d76159cbc597fbd756a23dcbb00f4d7290141042b4e8625a96127826915a5b109852636ad0da753c9e1d5606a50480cd0c40f1f8b8d898235e571fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff0280969800000000001976a9146963907531db72d0ed1a0cfb471ccb63923446f388ac80d6e34c000000001976a914f0688ba1c0d1ce182c7af6741e02658c7d4dfcd388ac000000000100000002c40297f730dd7b5a99567eb8d27b78758f607507c52292d02d4031895b52f2ff010000008b483045022100f7edfd4b0aac404e5bab4fd3889e0c6c41aa8d0e6fa122316f68eddd0a65013902205b09cc8b2d56e1cd1f7f2fafd60a129ed94504c4ac7bdc67b56fe67512658b3e014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffffca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb000000008a473044022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae740605658022006d1af525b9a14a35c003b78b72bd59738cd676f845d1ff3fc25049e01003614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffff01001ec4110200000043410469ab4181eceb28985b9b4e895c13fa5e68d85761b7eee311db5addef76fa8621865134a221bd01f28ec9999ee3e021e60766e9d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91c514655e2dc50633d1e4c84989f8aa90a0dbc883f0d23ed5c2fa010000008b48304502207ab51be6f12a1962ba0aaaf24a20e0b69b27a94fac5adf45aa7d2d18ffd9236102210086ae728b370e5329eead9accd880d0cb070aea0c96255fae6c4f1ddcce1fd56e014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad56529371864d9f6cb042faa06b588ac000000000100000001b4a47603e71b61bc3326efd90111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987dad92acb0c64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a038fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb6042034aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000"), SER_NETWORK, PROTOCOL_VERSION);
- stream >> block;
-
+ CBlock block = getBlock13b8a();
CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
// Match the last transaction
filter.insert(uint256S("0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20"));
CMerkleBlock merkleBlock(block, filter);
- BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
+ BOOST_CHECK_EQUAL(merkleBlock.header.GetHash().GetHex(), block.GetHash().GetHex());
- BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1);
+ BOOST_CHECK_EQUAL(merkleBlock.vMatchedTxn.size(), 1);
std::pair<unsigned int, uint256> pair = merkleBlock.vMatchedTxn[0];
BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20"));
@@ -463,7 +458,7 @@ BOOST_AUTO_TEST_CASE(merkle_block_4_test_update_none)
static std::vector<unsigned char> RandomData()
{
- uint256 r = GetRandHash();
+ uint256 r = InsecureRand256();
return std::vector<unsigned char>(r.begin(), r.end());
}
diff --git a/src/test/buildenv.py.in b/src/test/buildenv.py.in
deleted file mode 100644
index 153f34a3db..0000000000
--- a/src/test/buildenv.py.in
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/usr/bin/env python
-exeext="@EXEEXT@"
diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp
new file mode 100644
index 0000000000..6ae0bcadd0
--- /dev/null
+++ b/src/test/checkqueue_tests.cpp
@@ -0,0 +1,442 @@
+// Copyright (c) 2012-2017 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 "util.h"
+#include "utiltime.h"
+#include "validation.h"
+
+#include "test/test_bitcoin.h"
+#include "checkqueue.h"
+#include <boost/test/unit_test.hpp>
+#include <boost/thread.hpp>
+#include <atomic>
+#include <thread>
+#include <vector>
+#include <mutex>
+#include <condition_variable>
+
+#include <unordered_set>
+#include <memory>
+#include "random.h"
+
+// BasicTestingSetup not sufficient because nScriptCheckThreads is not set
+// otherwise.
+BOOST_FIXTURE_TEST_SUITE(checkqueue_tests, TestingSetup)
+
+static const int QUEUE_BATCH_SIZE = 128;
+
+struct FakeCheck {
+ bool operator()()
+ {
+ return true;
+ }
+ void swap(FakeCheck& x){};
+};
+
+struct FakeCheckCheckCompletion {
+ static std::atomic<size_t> n_calls;
+ bool operator()()
+ {
+ ++n_calls;
+ return true;
+ }
+ void swap(FakeCheckCheckCompletion& x){};
+};
+
+struct FailingCheck {
+ bool fails;
+ FailingCheck(bool _fails) : fails(_fails){};
+ FailingCheck() : fails(true){};
+ bool operator()()
+ {
+ return !fails;
+ }
+ void swap(FailingCheck& x)
+ {
+ std::swap(fails, x.fails);
+ };
+};
+
+struct UniqueCheck {
+ static std::mutex m;
+ static std::unordered_multiset<size_t> results;
+ size_t check_id;
+ UniqueCheck(size_t check_id_in) : check_id(check_id_in){};
+ UniqueCheck() : check_id(0){};
+ bool operator()()
+ {
+ std::lock_guard<std::mutex> l(m);
+ results.insert(check_id);
+ return true;
+ }
+ void swap(UniqueCheck& x) { std::swap(x.check_id, check_id); };
+};
+
+
+struct MemoryCheck {
+ static std::atomic<size_t> fake_allocated_memory;
+ bool b {false};
+ bool operator()()
+ {
+ return true;
+ }
+ MemoryCheck(){};
+ MemoryCheck(const MemoryCheck& x)
+ {
+ // We have to do this to make sure that destructor calls are paired
+ //
+ // Really, copy constructor should be deletable, but CCheckQueue breaks
+ // if it is deleted because of internal push_back.
+ fake_allocated_memory += b;
+ };
+ MemoryCheck(bool b_) : b(b_)
+ {
+ fake_allocated_memory += b;
+ };
+ ~MemoryCheck(){
+ fake_allocated_memory -= b;
+
+ };
+ void swap(MemoryCheck& x) { std::swap(b, x.b); };
+};
+
+struct FrozenCleanupCheck {
+ static std::atomic<uint64_t> nFrozen;
+ static std::condition_variable cv;
+ static std::mutex m;
+ // Freezing can't be the default initialized behavior given how the queue
+ // swaps in default initialized Checks.
+ bool should_freeze {false};
+ bool operator()()
+ {
+ return true;
+ }
+ FrozenCleanupCheck() {}
+ ~FrozenCleanupCheck()
+ {
+ if (should_freeze) {
+ std::unique_lock<std::mutex> l(m);
+ nFrozen = 1;
+ cv.notify_one();
+ cv.wait(l, []{ return nFrozen == 0;});
+ }
+ }
+ void swap(FrozenCleanupCheck& x){std::swap(should_freeze, x.should_freeze);};
+};
+
+// Static Allocations
+std::mutex FrozenCleanupCheck::m{};
+std::atomic<uint64_t> FrozenCleanupCheck::nFrozen{0};
+std::condition_variable FrozenCleanupCheck::cv{};
+std::mutex UniqueCheck::m;
+std::unordered_multiset<size_t> UniqueCheck::results;
+std::atomic<size_t> FakeCheckCheckCompletion::n_calls{0};
+std::atomic<size_t> MemoryCheck::fake_allocated_memory{0};
+
+// Queue Typedefs
+typedef CCheckQueue<FakeCheckCheckCompletion> Correct_Queue;
+typedef CCheckQueue<FakeCheck> Standard_Queue;
+typedef CCheckQueue<FailingCheck> Failing_Queue;
+typedef CCheckQueue<UniqueCheck> Unique_Queue;
+typedef CCheckQueue<MemoryCheck> Memory_Queue;
+typedef CCheckQueue<FrozenCleanupCheck> FrozenCleanup_Queue;
+
+
+/** This test case checks that the CCheckQueue works properly
+ * with each specified size_t Checks pushed.
+ */
+void Correct_Queue_range(std::vector<size_t> range)
+{
+ auto small_queue = std::unique_ptr<Correct_Queue>(new Correct_Queue {QUEUE_BATCH_SIZE});
+ boost::thread_group tg;
+ for (auto x = 0; x < nScriptCheckThreads; ++x) {
+ tg.create_thread([&]{small_queue->Thread();});
+ }
+ // Make vChecks here to save on malloc (this test can be slow...)
+ std::vector<FakeCheckCheckCompletion> vChecks;
+ for (auto i : range) {
+ size_t total = i;
+ FakeCheckCheckCompletion::n_calls = 0;
+ CCheckQueueControl<FakeCheckCheckCompletion> control(small_queue.get());
+ while (total) {
+ vChecks.resize(std::min(total, (size_t) InsecureRandRange(10)));
+ total -= vChecks.size();
+ control.Add(vChecks);
+ }
+ BOOST_REQUIRE(control.Wait());
+ if (FakeCheckCheckCompletion::n_calls != i) {
+ BOOST_REQUIRE_EQUAL(FakeCheckCheckCompletion::n_calls, i);
+ BOOST_TEST_MESSAGE("Failure on trial " << i << " expected, got " << FakeCheckCheckCompletion::n_calls);
+ }
+ }
+ tg.interrupt_all();
+ tg.join_all();
+}
+
+/** Test that 0 checks is correct
+ */
+BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Zero)
+{
+ std::vector<size_t> range;
+ range.push_back((size_t)0);
+ Correct_Queue_range(range);
+}
+/** Test that 1 check is correct
+ */
+BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_One)
+{
+ std::vector<size_t> range;
+ range.push_back((size_t)1);
+ Correct_Queue_range(range);
+}
+/** Test that MAX check is correct
+ */
+BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Max)
+{
+ std::vector<size_t> range;
+ range.push_back(100000);
+ Correct_Queue_range(range);
+}
+/** Test that random numbers of checks are correct
+ */
+BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Random)
+{
+ std::vector<size_t> range;
+ range.reserve(100000/1000);
+ for (size_t i = 2; i < 100000; i += std::max((size_t)1, (size_t)InsecureRandRange(std::min((size_t)1000, ((size_t)100000) - i))))
+ range.push_back(i);
+ Correct_Queue_range(range);
+}
+
+
+/** Test that failing checks are caught */
+BOOST_AUTO_TEST_CASE(test_CheckQueue_Catches_Failure)
+{
+ auto fail_queue = std::unique_ptr<Failing_Queue>(new Failing_Queue {QUEUE_BATCH_SIZE});
+
+ boost::thread_group tg;
+ for (auto x = 0; x < nScriptCheckThreads; ++x) {
+ tg.create_thread([&]{fail_queue->Thread();});
+ }
+
+ for (size_t i = 0; i < 1001; ++i) {
+ CCheckQueueControl<FailingCheck> control(fail_queue.get());
+ size_t remaining = i;
+ while (remaining) {
+ size_t r = InsecureRandRange(10);
+
+ std::vector<FailingCheck> vChecks;
+ vChecks.reserve(r);
+ for (size_t k = 0; k < r && remaining; k++, remaining--)
+ vChecks.emplace_back(remaining == 1);
+ control.Add(vChecks);
+ }
+ bool success = control.Wait();
+ if (i > 0) {
+ BOOST_REQUIRE(!success);
+ } else if (i == 0) {
+ BOOST_REQUIRE(success);
+ }
+ }
+ tg.interrupt_all();
+ tg.join_all();
+}
+// Test that a block validation which fails does not interfere with
+// future blocks, ie, the bad state is cleared.
+BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure)
+{
+ auto fail_queue = std::unique_ptr<Failing_Queue>(new Failing_Queue {QUEUE_BATCH_SIZE});
+ boost::thread_group tg;
+ for (auto x = 0; x < nScriptCheckThreads; ++x) {
+ tg.create_thread([&]{fail_queue->Thread();});
+ }
+
+ for (auto times = 0; times < 10; ++times) {
+ for (bool end_fails : {true, false}) {
+ CCheckQueueControl<FailingCheck> control(fail_queue.get());
+ {
+ std::vector<FailingCheck> vChecks;
+ vChecks.resize(100, false);
+ vChecks[99] = end_fails;
+ control.Add(vChecks);
+ }
+ bool r =control.Wait();
+ BOOST_REQUIRE(r || end_fails);
+ }
+ }
+ tg.interrupt_all();
+ tg.join_all();
+}
+
+// Test that unique checks are actually all called individually, rather than
+// just one check being called repeatedly. Test that checks are not called
+// more than once as well
+BOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck)
+{
+ auto queue = std::unique_ptr<Unique_Queue>(new Unique_Queue {QUEUE_BATCH_SIZE});
+ boost::thread_group tg;
+ for (auto x = 0; x < nScriptCheckThreads; ++x) {
+ tg.create_thread([&]{queue->Thread();});
+
+ }
+
+ size_t COUNT = 100000;
+ size_t total = COUNT;
+ {
+ CCheckQueueControl<UniqueCheck> control(queue.get());
+ while (total) {
+ size_t r = InsecureRandRange(10);
+ std::vector<UniqueCheck> vChecks;
+ for (size_t k = 0; k < r && total; k++)
+ vChecks.emplace_back(--total);
+ control.Add(vChecks);
+ }
+ }
+ bool r = true;
+ BOOST_REQUIRE_EQUAL(UniqueCheck::results.size(), COUNT);
+ for (size_t i = 0; i < COUNT; ++i)
+ r = r && UniqueCheck::results.count(i) == 1;
+ BOOST_REQUIRE(r);
+ tg.interrupt_all();
+ tg.join_all();
+}
+
+
+// Test that blocks which might allocate lots of memory free their memory aggressively.
+//
+// This test attempts to catch a pathological case where by lazily freeing
+// checks might mean leaving a check un-swapped out, and decreasing by 1 each
+// time could leave the data hanging across a sequence of blocks.
+BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory)
+{
+ auto queue = std::unique_ptr<Memory_Queue>(new Memory_Queue {QUEUE_BATCH_SIZE});
+ boost::thread_group tg;
+ for (auto x = 0; x < nScriptCheckThreads; ++x) {
+ tg.create_thread([&]{queue->Thread();});
+ }
+ for (size_t i = 0; i < 1000; ++i) {
+ size_t total = i;
+ {
+ CCheckQueueControl<MemoryCheck> control(queue.get());
+ while (total) {
+ size_t r = InsecureRandRange(10);
+ std::vector<MemoryCheck> vChecks;
+ for (size_t k = 0; k < r && total; k++) {
+ total--;
+ // Each iteration leaves data at the front, back, and middle
+ // to catch any sort of deallocation failure
+ vChecks.emplace_back(total == 0 || total == i || total == i/2);
+ }
+ control.Add(vChecks);
+ }
+ }
+ BOOST_REQUIRE_EQUAL(MemoryCheck::fake_allocated_memory, 0);
+ }
+ tg.interrupt_all();
+ tg.join_all();
+}
+
+// Test that a new verification cannot occur until all checks
+// have been destructed
+BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup)
+{
+ auto queue = std::unique_ptr<FrozenCleanup_Queue>(new FrozenCleanup_Queue {QUEUE_BATCH_SIZE});
+ boost::thread_group tg;
+ bool fails = false;
+ for (auto x = 0; x < nScriptCheckThreads; ++x) {
+ tg.create_thread([&]{queue->Thread();});
+ }
+ std::thread t0([&]() {
+ CCheckQueueControl<FrozenCleanupCheck> control(queue.get());
+ std::vector<FrozenCleanupCheck> vChecks(1);
+ // Freezing can't be the default initialized behavior given how the queue
+ // swaps in default initialized Checks (otherwise freezing destructor
+ // would get called twice).
+ vChecks[0].should_freeze = true;
+ control.Add(vChecks);
+ control.Wait(); // Hangs here
+ });
+ {
+ std::unique_lock<std::mutex> l(FrozenCleanupCheck::m);
+ // Wait until the queue has finished all jobs and frozen
+ FrozenCleanupCheck::cv.wait(l, [](){return FrozenCleanupCheck::nFrozen == 1;});
+ // Try to get control of the queue a bunch of times
+ for (auto x = 0; x < 100 && !fails; ++x) {
+ fails = queue->ControlMutex.try_lock();
+ }
+ // Unfreeze
+ FrozenCleanupCheck::nFrozen = 0;
+ }
+ // Awaken frozen destructor
+ FrozenCleanupCheck::cv.notify_one();
+ // Wait for control to finish
+ t0.join();
+ tg.interrupt_all();
+ tg.join_all();
+ BOOST_REQUIRE(!fails);
+}
+
+
+/** Test that CCheckQueueControl is threadsafe */
+BOOST_AUTO_TEST_CASE(test_CheckQueueControl_Locks)
+{
+ auto queue = std::unique_ptr<Standard_Queue>(new Standard_Queue{QUEUE_BATCH_SIZE});
+ {
+ boost::thread_group tg;
+ std::atomic<int> nThreads {0};
+ std::atomic<int> fails {0};
+ for (size_t i = 0; i < 3; ++i) {
+ tg.create_thread(
+ [&]{
+ CCheckQueueControl<FakeCheck> control(queue.get());
+ // While sleeping, no other thread should execute to this point
+ auto observed = ++nThreads;
+ MilliSleep(10);
+ fails += observed != nThreads;
+ });
+ }
+ tg.join_all();
+ BOOST_REQUIRE_EQUAL(fails, 0);
+ }
+ {
+ boost::thread_group tg;
+ std::mutex m;
+ std::condition_variable cv;
+ {
+ bool has_lock {false};
+ bool has_tried {false};
+ bool done {false};
+ bool done_ack {false};
+ std::unique_lock<std::mutex> l(m);
+ tg.create_thread([&]{
+ CCheckQueueControl<FakeCheck> control(queue.get());
+ std::unique_lock<std::mutex> ll(m);
+ has_lock = true;
+ cv.notify_one();
+ cv.wait(ll, [&]{return has_tried;});
+ done = true;
+ cv.notify_one();
+ // Wait until the done is acknowledged
+ //
+ cv.wait(ll, [&]{return done_ack;});
+ });
+ // Wait for thread to get the lock
+ cv.wait(l, [&](){return has_lock;});
+ bool fails = false;
+ for (auto x = 0; x < 100 && !fails; ++x) {
+ fails = queue->ControlMutex.try_lock();
+ }
+ has_tried = true;
+ cv.notify_one();
+ cv.wait(l, [&](){return done;});
+ // Acknowledge the done
+ done_ack = true;
+ cv.notify_one();
+ BOOST_REQUIRE(!fails);
+ }
+ tg.join_all();
+ }
+}
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index b25c7ccc51..dc358bff95 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -8,7 +8,6 @@
#include "undo.h"
#include "utilstrencodings.h"
#include "test/test_bitcoin.h"
-#include "test/test_random.h"
#include "validation.h"
#include "consensus/validation.h"
@@ -17,46 +16,49 @@
#include <boost/test/unit_test.hpp>
-bool ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, const COutPoint& out);
+int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out);
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, int nHeight);
namespace
{
+//! equality test
+bool operator==(const Coin &a, const Coin &b) {
+ // Empty Coin objects are always equal.
+ if (a.IsSpent() && b.IsSpent()) return true;
+ return a.fCoinBase == b.fCoinBase &&
+ a.nHeight == b.nHeight &&
+ a.out == b.out;
+}
+
class CCoinsViewTest : public CCoinsView
{
uint256 hashBestBlock_;
- std::map<uint256, CCoins> map_;
+ std::map<COutPoint, Coin> map_;
public:
- bool GetCoins(const uint256& txid, CCoins& coins) const
+ bool GetCoin(const COutPoint& outpoint, Coin& coin) const override
{
- std::map<uint256, CCoins>::const_iterator it = map_.find(txid);
+ std::map<COutPoint, Coin>::const_iterator it = map_.find(outpoint);
if (it == map_.end()) {
return false;
}
- coins = it->second;
- if (coins.IsPruned() && insecure_rand() % 2 == 0) {
+ coin = it->second;
+ if (coin.IsSpent() && InsecureRandBool() == 0) {
// Randomly return false in case of an empty entry.
return false;
}
return true;
}
- bool HaveCoins(const uint256& txid) const
- {
- CCoins coins;
- return GetCoins(txid, coins);
- }
-
- uint256 GetBestBlock() const { return hashBestBlock_; }
+ uint256 GetBestBlock() const override { return hashBestBlock_; }
- bool BatchWrite(CCoinsMap& mapCoins, const uint256& hashBlock)
+ bool BatchWrite(CCoinsMap& mapCoins, const uint256& hashBlock) override
{
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); ) {
if (it->second.flags & CCoinsCacheEntry::DIRTY) {
// Same optimization used in CCoinsViewDB is to only write dirty entries.
- map_[it->first] = it->second.coins;
- if (it->second.coins.IsPruned() && insecure_rand() % 3 == 0) {
+ map_[it->first] = it->second.coin;
+ if (it->second.coin.IsSpent() && InsecureRandRange(3) == 0) {
// Randomly delete empty entries on write.
map_.erase(it->first);
}
@@ -72,23 +74,26 @@ public:
class CCoinsViewCacheTest : public CCoinsViewCache
{
public:
- CCoinsViewCacheTest(CCoinsView* base) : CCoinsViewCache(base) {}
+ explicit 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);
+ size_t count = 0;
for (CCoinsMap::iterator it = cacheCoins.begin(); it != cacheCoins.end(); it++) {
- ret += it->second.coins.DynamicMemoryUsage();
+ ret += it->second.coin.DynamicMemoryUsage();
+ ++count;
}
+ BOOST_CHECK_EQUAL(GetCacheSize(), count);
BOOST_CHECK_EQUAL(DynamicMemoryUsage(), ret);
}
- CCoinsMap& map() { return cacheCoins; }
- size_t& usage() { return cachedCoinsUsage; }
+ CCoinsMap& map() const { return cacheCoins; }
+ size_t& usage() const { return cachedCoinsUsage; }
};
-}
+} // namespace
BOOST_FIXTURE_TEST_SUITE(coins_tests, BasicTestingSetup)
@@ -97,7 +102,7 @@ static const unsigned int NUM_SIMULATION_ITERATIONS = 40000;
// This is a large randomized insert/remove simulation test on a variable-size
// stack of caches on top of CCoinsViewTest.
//
-// It will randomly create/update/delete CCoins entries to a tip of caches, with
+// It will randomly create/update/delete Coin entries to a tip of caches, with
// txids picked from a limited list of random 256-bit hashes. Occasionally, a
// new tip is added to the stack of caches, or the tip is flushed and removed.
//
@@ -109,13 +114,15 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
bool removed_all_caches = false;
bool reached_4_caches = false;
bool added_an_entry = false;
+ bool added_an_unspendable_entry = false;
bool removed_an_entry = false;
bool updated_an_entry = false;
bool found_an_entry = false;
bool missed_an_entry = false;
+ bool uncached_an_entry = false;
// A simple map to track what we expect the cache stack to represent.
- std::map<uint256, CCoins> result;
+ std::map<COutPoint, Coin> result;
// The cache stack.
CCoinsViewTest base; // A CCoinsViewTest at the bottom.
@@ -126,66 +133,95 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
std::vector<uint256> txids;
txids.resize(NUM_SIMULATION_ITERATIONS / 8);
for (unsigned int i = 0; i < txids.size(); i++) {
- txids[i] = GetRandHash();
+ txids[i] = InsecureRand256();
}
for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) {
// Do a random modification.
{
- uint256 txid = txids[insecure_rand() % txids.size()]; // txid we're going to modify in this iteration.
- CCoins& coins = result[txid];
- CCoinsModifier entry = stack.back()->ModifyCoins(txid);
- BOOST_CHECK(coins == *entry);
- if (insecure_rand() % 5 == 0 || coins.IsPruned()) {
- if (coins.IsPruned()) {
- added_an_entry = true;
+ uint256 txid = txids[InsecureRandRange(txids.size())]; // txid we're going to modify in this iteration.
+ Coin& coin = result[COutPoint(txid, 0)];
+
+ // Determine whether to test HaveCoin before or after Access* (or both). As these functions
+ // can influence each other's behaviour by pulling things into the cache, all combinations
+ // are tested.
+ bool test_havecoin_before = InsecureRandBits(2) == 0;
+ bool test_havecoin_after = InsecureRandBits(2) == 0;
+
+ bool result_havecoin = test_havecoin_before ? stack.back()->HaveCoin(COutPoint(txid, 0)) : false;
+ const Coin& entry = (InsecureRandRange(500) == 0) ? AccessByTxid(*stack.back(), txid) : stack.back()->AccessCoin(COutPoint(txid, 0));
+ BOOST_CHECK(coin == entry);
+ BOOST_CHECK(!test_havecoin_before || result_havecoin == !entry.IsSpent());
+
+ if (test_havecoin_after) {
+ bool ret = stack.back()->HaveCoin(COutPoint(txid, 0));
+ BOOST_CHECK(ret == !entry.IsSpent());
+ }
+
+ if (InsecureRandRange(5) == 0 || coin.IsSpent()) {
+ Coin newcoin;
+ newcoin.out.nValue = InsecureRand32();
+ newcoin.nHeight = 1;
+ if (InsecureRandRange(16) == 0 && coin.IsSpent()) {
+ newcoin.out.scriptPubKey.assign(1 + InsecureRandBits(6), OP_RETURN);
+ BOOST_CHECK(newcoin.out.scriptPubKey.IsUnspendable());
+ added_an_unspendable_entry = true;
} else {
- updated_an_entry = true;
+ newcoin.out.scriptPubKey.assign(InsecureRandBits(6), 0); // Random sizes so we can test memory usage accounting
+ (coin.IsSpent() ? added_an_entry : updated_an_entry) = true;
+ coin = newcoin;
}
- coins.nVersion = insecure_rand();
- coins.vout.resize(1);
- coins.vout[0].nValue = insecure_rand();
- *entry = coins;
+ stack.back()->AddCoin(COutPoint(txid, 0), std::move(newcoin), !coin.IsSpent() || InsecureRand32() & 1);
} else {
- coins.Clear();
- entry->Clear();
removed_an_entry = true;
+ coin.Clear();
+ stack.back()->SpendCoin(COutPoint(txid, 0));
}
}
+ // One every 10 iterations, remove a random entry from the cache
+ if (InsecureRandRange(10) == 0) {
+ COutPoint out(txids[InsecureRand32() % txids.size()], 0);
+ int cacheid = InsecureRand32() % stack.size();
+ stack[cacheid]->Uncache(out);
+ uncached_an_entry |= !stack[cacheid]->HaveCoinInCache(out);
+ }
+
// Once every 1000 iterations and at the end, verify the full cache.
- if (insecure_rand() % 1000 == 1 || i == NUM_SIMULATION_ITERATIONS - 1) {
- for (std::map<uint256, CCoins>::iterator it = result.begin(); it != result.end(); it++) {
- const CCoins* coins = stack.back()->AccessCoins(it->first);
- if (coins) {
- BOOST_CHECK(*coins == it->second);
- found_an_entry = true;
- } else {
- BOOST_CHECK(it->second.IsPruned());
+ if (InsecureRandRange(1000) == 1 || i == NUM_SIMULATION_ITERATIONS - 1) {
+ for (auto it = result.begin(); it != result.end(); it++) {
+ bool have = stack.back()->HaveCoin(it->first);
+ const Coin& coin = stack.back()->AccessCoin(it->first);
+ BOOST_CHECK(have == !coin.IsSpent());
+ BOOST_CHECK(coin == it->second);
+ if (coin.IsSpent()) {
missed_an_entry = true;
+ } else {
+ BOOST_CHECK(stack.back()->HaveCoinInCache(it->first));
+ found_an_entry = true;
}
}
- BOOST_FOREACH(const CCoinsViewCacheTest *test, stack) {
+ for (const CCoinsViewCacheTest *test : stack) {
test->SelfTest();
}
}
- if (insecure_rand() % 100 == 0) {
+ if (InsecureRandRange(100) == 0) {
// Every 100 iterations, flush an intermediate cache
- if (stack.size() > 1 && insecure_rand() % 2 == 0) {
- unsigned int flushIndex = insecure_rand() % (stack.size() - 1);
+ if (stack.size() > 1 && InsecureRandBool() == 0) {
+ unsigned int flushIndex = InsecureRandRange(stack.size() - 1);
stack[flushIndex]->Flush();
}
}
- if (insecure_rand() % 100 == 0) {
+ if (InsecureRandRange(100) == 0) {
// Every 100 iterations, change the cache stack.
- if (stack.size() > 0 && insecure_rand() % 2 == 0) {
+ if (stack.size() > 0 && InsecureRandBool() == 0) {
//Remove the top cache
stack.back()->Flush();
delete stack.back();
stack.pop_back();
}
- if (stack.size() == 0 || (stack.size() < 4 && insecure_rand() % 2)) {
+ if (stack.size() == 0 || (stack.size() < 4 && InsecureRandBool())) {
//Add a new cache
CCoinsView* tip = &base;
if (stack.size() > 0) {
@@ -211,25 +247,27 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
BOOST_CHECK(removed_all_caches);
BOOST_CHECK(reached_4_caches);
BOOST_CHECK(added_an_entry);
+ BOOST_CHECK(added_an_unspendable_entry);
BOOST_CHECK(removed_an_entry);
BOOST_CHECK(updated_an_entry);
BOOST_CHECK(found_an_entry);
BOOST_CHECK(missed_an_entry);
+ BOOST_CHECK(uncached_an_entry);
}
-typedef std::tuple<CTransaction,CTxUndo,CCoins> TxData;
// Store of all necessary tx and undo data for next test
-std::map<uint256, TxData> alltxs;
-
-TxData &FindRandomFrom(const std::set<uint256> &txidset) {
- assert(txidset.size());
- std::set<uint256>::iterator txIt = txidset.lower_bound(GetRandHash());
- if (txIt == txidset.end()) {
- txIt = txidset.begin();
+typedef std::map<COutPoint, std::tuple<CTransaction,CTxUndo,Coin>> UtxoData;
+UtxoData utxoData;
+
+UtxoData::iterator FindRandomFrom(const std::set<COutPoint> &utxoSet) {
+ assert(utxoSet.size());
+ auto utxoSetIt = utxoSet.lower_bound(COutPoint(InsecureRand256(), 0));
+ if (utxoSetIt == utxoSet.end()) {
+ utxoSetIt = utxoSet.begin();
}
- std::map<uint256, TxData>::iterator txdit = alltxs.find(*txIt);
- assert(txdit != alltxs.end());
- return txdit->second;
+ auto utxoDataIt = utxoData.find(*utxoSetIt);
+ assert(utxoDataIt != utxoData.end());
+ return utxoDataIt;
}
@@ -237,12 +275,12 @@ TxData &FindRandomFrom(const std::set<uint256> &txidset) {
// except the emphasis is on testing the functionality of UpdateCoins
// random txs are created and UpdateCoins is used to update the cache stack
// In particular it is tested that spending a duplicate coinbase tx
-// has the expected effect (the other duplicate is overwitten at all cache levels)
+// has the expected effect (the other duplicate is overwritten at all cache levels)
BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
{
bool spent_a_duplicate_coinbase = false;
// A simple map to track what we expect the cache stack to represent.
- std::map<uint256, CCoins> result;
+ std::map<COutPoint, Coin> result;
// The cache stack.
CCoinsViewTest base; // A CCoinsViewTest at the bottom.
@@ -250,13 +288,13 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
stack.push_back(new CCoinsViewCacheTest(&base)); // Start with one cache.
// Track the txids we've used in various sets
- std::set<uint256> coinbaseids;
- std::set<uint256> disconnectedids;
- std::set<uint256> duplicateids;
- std::set<uint256> utxoset;
+ std::set<COutPoint> coinbase_coins;
+ std::set<COutPoint> disconnected_coins;
+ std::set<COutPoint> duplicate_coins;
+ std::set<COutPoint> utxoset;
for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) {
- uint32_t randiter = insecure_rand();
+ uint32_t randiter = InsecureRand32();
// 19/20 txs add a new transaction
if (randiter % 20 < 19) {
@@ -264,23 +302,24 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
tx.vin.resize(1);
tx.vout.resize(1);
tx.vout[0].nValue = i; //Keep txs unique unless intended to duplicate
- unsigned int height = insecure_rand();
- CCoins oldcoins;
+ tx.vout[0].scriptPubKey.assign(InsecureRand32() & 0x3F, 0); // Random sizes so we can test memory usage accounting
+ unsigned int height = InsecureRand32();
+ Coin old_coin;
// 2/20 times create a new coinbase
- if (randiter % 20 < 2 || coinbaseids.size() < 10) {
+ if (randiter % 20 < 2 || coinbase_coins.size() < 10) {
// 1/10 of those times create a duplicate coinbase
- if (insecure_rand() % 10 == 0 && coinbaseids.size()) {
- TxData &txd = FindRandomFrom(coinbaseids);
+ if (InsecureRandRange(10) == 0 && coinbase_coins.size()) {
+ auto utxod = FindRandomFrom(coinbase_coins);
// Reuse the exact same coinbase
- tx = std::get<0>(txd);
+ tx = std::get<0>(utxod->second);
// shouldn't be available for reconnection if its been duplicated
- disconnectedids.erase(tx.GetHash());
+ disconnected_coins.erase(utxod->first);
- duplicateids.insert(tx.GetHash());
+ duplicate_coins.insert(utxod->first);
}
else {
- coinbaseids.insert(tx.GetHash());
+ coinbase_coins.insert(COutPoint(tx.GetHash(), 0));
}
assert(CTransaction(tx).IsCoinBase());
}
@@ -288,129 +327,133 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
// 17/20 times reconnect previous or add a regular tx
else {
- uint256 prevouthash;
+ COutPoint prevout;
// 1/20 times reconnect a previously disconnected tx
- if (randiter % 20 == 2 && disconnectedids.size()) {
- TxData &txd = FindRandomFrom(disconnectedids);
- tx = std::get<0>(txd);
- prevouthash = tx.vin[0].prevout.hash;
- if (!CTransaction(tx).IsCoinBase() && !utxoset.count(prevouthash)) {
- disconnectedids.erase(tx.GetHash());
+ if (randiter % 20 == 2 && disconnected_coins.size()) {
+ auto utxod = FindRandomFrom(disconnected_coins);
+ tx = std::get<0>(utxod->second);
+ prevout = tx.vin[0].prevout;
+ if (!CTransaction(tx).IsCoinBase() && !utxoset.count(prevout)) {
+ disconnected_coins.erase(utxod->first);
continue;
}
// If this tx is already IN the UTXO, then it must be a coinbase, and it must be a duplicate
- if (utxoset.count(tx.GetHash())) {
+ if (utxoset.count(utxod->first)) {
assert(CTransaction(tx).IsCoinBase());
- assert(duplicateids.count(tx.GetHash()));
+ assert(duplicate_coins.count(utxod->first));
}
- disconnectedids.erase(tx.GetHash());
+ disconnected_coins.erase(utxod->first);
}
// 16/20 times create a regular tx
else {
- TxData &txd = FindRandomFrom(utxoset);
- prevouthash = std::get<0>(txd).GetHash();
+ auto utxod = FindRandomFrom(utxoset);
+ prevout = utxod->first;
// Construct the tx to spend the coins of prevouthash
- tx.vin[0].prevout.hash = prevouthash;
- tx.vin[0].prevout.n = 0;
+ tx.vin[0].prevout = prevout;
assert(!CTransaction(tx).IsCoinBase());
}
// In this simple test coins only have two states, spent or unspent, save the unspent state to restore
- oldcoins = result[prevouthash];
+ old_coin = result[prevout];
// Update the expected result of prevouthash to know these coins are spent
- result[prevouthash].Clear();
+ result[prevout].Clear();
- utxoset.erase(prevouthash);
+ utxoset.erase(prevout);
// The test is designed to ensure spending a duplicate coinbase will work properly
// if that ever happens and not resurrect the previously overwritten coinbase
- if (duplicateids.count(prevouthash))
+ if (duplicate_coins.count(prevout)) {
spent_a_duplicate_coinbase = true;
+ }
}
// Update the expected result to know about the new output coins
- result[tx.GetHash()].FromTx(tx, height);
+ assert(tx.vout.size() == 1);
+ const COutPoint outpoint(tx.GetHash(), 0);
+ result[outpoint] = Coin(tx.vout[0], height, CTransaction(tx).IsCoinBase());
// Call UpdateCoins on the top cache
CTxUndo undo;
UpdateCoins(tx, *(stack.back()), undo, height);
// Update the utxo set for future spends
- utxoset.insert(tx.GetHash());
+ utxoset.insert(outpoint);
// Track this tx and undo info to use later
- alltxs.insert(std::make_pair(tx.GetHash(),std::make_tuple(tx,undo,oldcoins)));
- }
-
- //1/20 times undo a previous transaction
- else if (utxoset.size()) {
- TxData &txd = FindRandomFrom(utxoset);
-
- CTransaction &tx = std::get<0>(txd);
- CTxUndo &undo = std::get<1>(txd);
- CCoins &origcoins = std::get<2>(txd);
+ utxoData.emplace(outpoint, std::make_tuple(tx,undo,old_coin));
+ } else if (utxoset.size()) {
+ //1/20 times undo a previous transaction
+ auto utxod = FindRandomFrom(utxoset);
- uint256 undohash = tx.GetHash();
+ CTransaction &tx = std::get<0>(utxod->second);
+ CTxUndo &undo = std::get<1>(utxod->second);
+ Coin &orig_coin = std::get<2>(utxod->second);
// Update the expected result
// Remove new outputs
- result[undohash].Clear();
+ result[utxod->first].Clear();
// If not coinbase restore prevout
if (!tx.IsCoinBase()) {
- result[tx.vin[0].prevout.hash] = origcoins;
+ result[tx.vin[0].prevout] = orig_coin;
}
// Disconnect the tx from the current UTXO
// See code in DisconnectBlock
// remove outputs
- {
- CCoinsModifier outs = stack.back()->ModifyCoins(undohash);
- outs->Clear();
- }
+ stack.back()->SpendCoin(utxod->first);
// restore inputs
if (!tx.IsCoinBase()) {
const COutPoint &out = tx.vin[0].prevout;
- const CTxInUndo &undoin = undo.vprevout[0];
- ApplyTxInUndo(undoin, *(stack.back()), out);
+ Coin coin = undo.vprevout[0];
+ ApplyTxInUndo(std::move(coin), *(stack.back()), out);
}
// Store as a candidate for reconnection
- disconnectedids.insert(undohash);
+ disconnected_coins.insert(utxod->first);
// Update the utxoset
- utxoset.erase(undohash);
+ utxoset.erase(utxod->first);
if (!tx.IsCoinBase())
- utxoset.insert(tx.vin[0].prevout.hash);
+ utxoset.insert(tx.vin[0].prevout);
}
// Once every 1000 iterations and at the end, verify the full cache.
- if (insecure_rand() % 1000 == 1 || i == NUM_SIMULATION_ITERATIONS - 1) {
- for (std::map<uint256, CCoins>::iterator it = result.begin(); it != result.end(); it++) {
- const CCoins* coins = stack.back()->AccessCoins(it->first);
- if (coins) {
- BOOST_CHECK(*coins == it->second);
- } else {
- BOOST_CHECK(it->second.IsPruned());
- }
+ if (InsecureRandRange(1000) == 1 || i == NUM_SIMULATION_ITERATIONS - 1) {
+ for (auto it = result.begin(); it != result.end(); it++) {
+ bool have = stack.back()->HaveCoin(it->first);
+ const Coin& coin = stack.back()->AccessCoin(it->first);
+ BOOST_CHECK(have == !coin.IsSpent());
+ BOOST_CHECK(coin == it->second);
}
}
- if (insecure_rand() % 100 == 0) {
+ // One every 10 iterations, remove a random entry from the cache
+ if (utxoset.size() > 1 && InsecureRandRange(30) == 0) {
+ stack[InsecureRand32() % stack.size()]->Uncache(FindRandomFrom(utxoset)->first);
+ }
+ if (disconnected_coins.size() > 1 && InsecureRandRange(30) == 0) {
+ stack[InsecureRand32() % stack.size()]->Uncache(FindRandomFrom(disconnected_coins)->first);
+ }
+ if (duplicate_coins.size() > 1 && InsecureRandRange(30) == 0) {
+ stack[InsecureRand32() % stack.size()]->Uncache(FindRandomFrom(duplicate_coins)->first);
+ }
+
+ if (InsecureRandRange(100) == 0) {
// Every 100 iterations, flush an intermediate cache
- if (stack.size() > 1 && insecure_rand() % 2 == 0) {
- unsigned int flushIndex = insecure_rand() % (stack.size() - 1);
+ if (stack.size() > 1 && InsecureRandBool() == 0) {
+ unsigned int flushIndex = InsecureRandRange(stack.size() - 1);
stack[flushIndex]->Flush();
}
}
- if (insecure_rand() % 100 == 0) {
+ if (InsecureRandRange(100) == 0) {
// Every 100 iterations, change the cache stack.
- if (stack.size() > 0 && insecure_rand() % 2 == 0) {
+ if (stack.size() > 0 && InsecureRandBool() == 0) {
stack.back()->Flush();
delete stack.back();
stack.pop_back();
}
- if (stack.size() == 0 || (stack.size() < 4 && insecure_rand() % 2)) {
+ if (stack.size() == 0 || (stack.size() < 4 && InsecureRandBool())) {
CCoinsView* tip = &base;
if (stack.size() > 0) {
tip = stack.back();
@@ -433,53 +476,36 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
BOOST_AUTO_TEST_CASE(ccoins_serialization)
{
// Good example
- CDataStream ss1(ParseHex("0104835800816115944e077fe7c803cfa57f29b36bf87c1d358bb85e"), SER_DISK, CLIENT_VERSION);
- CCoins cc1;
+ CDataStream ss1(ParseHex("97f23c835800816115944e077fe7c803cfa57f29b36bf87c1d35"), SER_DISK, CLIENT_VERSION);
+ Coin cc1;
ss1 >> cc1;
- BOOST_CHECK_EQUAL(cc1.nVersion, 1);
BOOST_CHECK_EQUAL(cc1.fCoinBase, false);
BOOST_CHECK_EQUAL(cc1.nHeight, 203998);
- BOOST_CHECK_EQUAL(cc1.vout.size(), 2);
- BOOST_CHECK_EQUAL(cc1.IsAvailable(0), false);
- BOOST_CHECK_EQUAL(cc1.IsAvailable(1), true);
- BOOST_CHECK_EQUAL(cc1.vout[1].nValue, 60000000000ULL);
- BOOST_CHECK_EQUAL(HexStr(cc1.vout[1].scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex("816115944e077fe7c803cfa57f29b36bf87c1d35"))))));
+ BOOST_CHECK_EQUAL(cc1.out.nValue, 60000000000ULL);
+ BOOST_CHECK_EQUAL(HexStr(cc1.out.scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex("816115944e077fe7c803cfa57f29b36bf87c1d35"))))));
// Good example
- CDataStream ss2(ParseHex("0109044086ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4eebbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa486af3b"), SER_DISK, CLIENT_VERSION);
- CCoins cc2;
+ CDataStream ss2(ParseHex("8ddf77bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4"), SER_DISK, CLIENT_VERSION);
+ Coin cc2;
ss2 >> cc2;
- BOOST_CHECK_EQUAL(cc2.nVersion, 1);
BOOST_CHECK_EQUAL(cc2.fCoinBase, true);
BOOST_CHECK_EQUAL(cc2.nHeight, 120891);
- BOOST_CHECK_EQUAL(cc2.vout.size(), 17);
- for (int i = 0; i < 17; i++) {
- BOOST_CHECK_EQUAL(cc2.IsAvailable(i), i == 4 || i == 16);
- }
- BOOST_CHECK_EQUAL(cc2.vout[4].nValue, 234925952);
- BOOST_CHECK_EQUAL(HexStr(cc2.vout[4].scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex("61b01caab50f1b8e9c50a5057eb43c2d9563a4ee"))))));
- BOOST_CHECK_EQUAL(cc2.vout[16].nValue, 110397);
- BOOST_CHECK_EQUAL(HexStr(cc2.vout[16].scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex("8c988f1a4a4de2161e0f50aac7f17e7f9555caa4"))))));
+ BOOST_CHECK_EQUAL(cc2.out.nValue, 110397);
+ BOOST_CHECK_EQUAL(HexStr(cc2.out.scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex("8c988f1a4a4de2161e0f50aac7f17e7f9555caa4"))))));
// Smallest possible example
- CDataStream ssx(SER_DISK, CLIENT_VERSION);
- BOOST_CHECK_EQUAL(HexStr(ssx.begin(), ssx.end()), "");
-
- CDataStream ss3(ParseHex("0002000600"), SER_DISK, CLIENT_VERSION);
- CCoins cc3;
+ CDataStream ss3(ParseHex("000006"), SER_DISK, CLIENT_VERSION);
+ Coin cc3;
ss3 >> cc3;
- BOOST_CHECK_EQUAL(cc3.nVersion, 0);
BOOST_CHECK_EQUAL(cc3.fCoinBase, false);
BOOST_CHECK_EQUAL(cc3.nHeight, 0);
- BOOST_CHECK_EQUAL(cc3.vout.size(), 1);
- BOOST_CHECK_EQUAL(cc3.IsAvailable(0), true);
- BOOST_CHECK_EQUAL(cc3.vout[0].nValue, 0);
- BOOST_CHECK_EQUAL(cc3.vout[0].scriptPubKey.size(), 0);
+ BOOST_CHECK_EQUAL(cc3.out.nValue, 0);
+ BOOST_CHECK_EQUAL(cc3.out.scriptPubKey.size(), 0);
// scriptPubKey that ends beyond the end of the stream
- CDataStream ss4(ParseHex("0002000800"), SER_DISK, CLIENT_VERSION);
+ CDataStream ss4(ParseHex("000007"), SER_DISK, CLIENT_VERSION);
try {
- CCoins cc4;
+ Coin cc4;
ss4 >> cc4;
BOOST_CHECK_MESSAGE(false, "We should have thrown");
} catch (const std::ios_base::failure& e) {
@@ -490,16 +516,16 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization)
uint64_t x = 3000000000ULL;
tmp << VARINT(x);
BOOST_CHECK_EQUAL(HexStr(tmp.begin(), tmp.end()), "8a95c0bb00");
- CDataStream ss5(ParseHex("0002008a95c0bb0000"), SER_DISK, CLIENT_VERSION);
+ CDataStream ss5(ParseHex("00008a95c0bb00"), SER_DISK, CLIENT_VERSION);
try {
- CCoins cc5;
+ Coin cc5;
ss5 >> cc5;
BOOST_CHECK_MESSAGE(false, "We should have thrown");
} catch (const std::ios_base::failure& e) {
}
}
-const static uint256 TXID;
+const static COutPoint OUTPOINT;
const static CAmount PRUNED = -1;
const static CAmount ABSENT = -2;
const static CAmount FAIL = -3;
@@ -514,15 +540,15 @@ const static auto FLAGS = {char(0), FRESH, DIRTY, char(DIRTY | FRESH)};
const static auto CLEAN_FLAGS = {char(0), FRESH};
const static auto ABSENT_FLAGS = {NO_ENTRY};
-void SetCoinsValue(CAmount value, CCoins& coins)
+void SetCoinsValue(CAmount value, Coin& coin)
{
assert(value != ABSENT);
- coins.Clear();
- assert(coins.IsPruned());
+ coin.Clear();
+ assert(coin.IsSpent());
if (value != PRUNED) {
- coins.vout.emplace_back();
- coins.vout.back().nValue = value;
- assert(!coins.IsPruned());
+ coin.out.nValue = value;
+ coin.nHeight = 1;
+ assert(!coin.IsSpent());
}
}
@@ -535,25 +561,23 @@ size_t InsertCoinsMapEntry(CCoinsMap& map, CAmount value, char flags)
assert(flags != NO_ENTRY);
CCoinsCacheEntry entry;
entry.flags = flags;
- SetCoinsValue(value, entry.coins);
- auto inserted = map.emplace(TXID, std::move(entry));
+ SetCoinsValue(value, entry.coin);
+ auto inserted = map.emplace(OUTPOINT, std::move(entry));
assert(inserted.second);
- return inserted.first->second.coins.DynamicMemoryUsage();
+ return inserted.first->second.coin.DynamicMemoryUsage();
}
void GetCoinsMapEntry(const CCoinsMap& map, CAmount& value, char& flags)
{
- auto it = map.find(TXID);
+ auto it = map.find(OUTPOINT);
if (it == map.end()) {
value = ABSENT;
flags = NO_ENTRY;
} else {
- if (it->second.coins.IsPruned()) {
- assert(it->second.coins.vout.size() == 0);
+ if (it->second.coin.IsSpent()) {
value = PRUNED;
} else {
- assert(it->second.coins.vout.size() == 1);
- value = it->second.coins.vout[0].nValue;
+ value = it->second.coin.out.nValue;
}
flags = it->second.flags;
assert(flags != NO_ENTRY);
@@ -581,10 +605,10 @@ public:
CCoinsViewCacheTest cache{&base};
};
-void CheckAccessCoins(CAmount base_value, CAmount cache_value, CAmount expected_value, char cache_flags, char expected_flags)
+void CheckAccessCoin(CAmount base_value, CAmount cache_value, CAmount expected_value, char cache_flags, char expected_flags)
{
SingleEntryCacheTest test(base_value, cache_value, cache_flags);
- test.cache.AccessCoins(TXID);
+ test.cache.AccessCoin(OUTPOINT);
test.cache.SelfTest();
CAmount result_value;
@@ -603,39 +627,39 @@ BOOST_AUTO_TEST_CASE(ccoins_access)
* Base Cache Result Cache Result
* Value Value Value Flags Flags
*/
- CheckAccessCoins(ABSENT, ABSENT, ABSENT, NO_ENTRY , NO_ENTRY );
- CheckAccessCoins(ABSENT, PRUNED, PRUNED, 0 , 0 );
- CheckAccessCoins(ABSENT, PRUNED, PRUNED, FRESH , FRESH );
- CheckAccessCoins(ABSENT, PRUNED, PRUNED, DIRTY , DIRTY );
- CheckAccessCoins(ABSENT, PRUNED, PRUNED, DIRTY|FRESH, DIRTY|FRESH);
- CheckAccessCoins(ABSENT, VALUE2, VALUE2, 0 , 0 );
- CheckAccessCoins(ABSENT, VALUE2, VALUE2, FRESH , FRESH );
- CheckAccessCoins(ABSENT, VALUE2, VALUE2, DIRTY , DIRTY );
- CheckAccessCoins(ABSENT, VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH);
- CheckAccessCoins(PRUNED, ABSENT, PRUNED, NO_ENTRY , FRESH );
- CheckAccessCoins(PRUNED, PRUNED, PRUNED, 0 , 0 );
- CheckAccessCoins(PRUNED, PRUNED, PRUNED, FRESH , FRESH );
- CheckAccessCoins(PRUNED, PRUNED, PRUNED, DIRTY , DIRTY );
- CheckAccessCoins(PRUNED, PRUNED, PRUNED, DIRTY|FRESH, DIRTY|FRESH);
- CheckAccessCoins(PRUNED, VALUE2, VALUE2, 0 , 0 );
- CheckAccessCoins(PRUNED, VALUE2, VALUE2, FRESH , FRESH );
- CheckAccessCoins(PRUNED, VALUE2, VALUE2, DIRTY , DIRTY );
- CheckAccessCoins(PRUNED, VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH);
- CheckAccessCoins(VALUE1, ABSENT, VALUE1, NO_ENTRY , 0 );
- CheckAccessCoins(VALUE1, PRUNED, PRUNED, 0 , 0 );
- CheckAccessCoins(VALUE1, PRUNED, PRUNED, FRESH , FRESH );
- CheckAccessCoins(VALUE1, PRUNED, PRUNED, DIRTY , DIRTY );
- CheckAccessCoins(VALUE1, PRUNED, PRUNED, DIRTY|FRESH, DIRTY|FRESH);
- CheckAccessCoins(VALUE1, VALUE2, VALUE2, 0 , 0 );
- CheckAccessCoins(VALUE1, VALUE2, VALUE2, FRESH , FRESH );
- CheckAccessCoins(VALUE1, VALUE2, VALUE2, DIRTY , DIRTY );
- CheckAccessCoins(VALUE1, VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH);
+ CheckAccessCoin(ABSENT, ABSENT, ABSENT, NO_ENTRY , NO_ENTRY );
+ CheckAccessCoin(ABSENT, PRUNED, PRUNED, 0 , 0 );
+ CheckAccessCoin(ABSENT, PRUNED, PRUNED, FRESH , FRESH );
+ CheckAccessCoin(ABSENT, PRUNED, PRUNED, DIRTY , DIRTY );
+ CheckAccessCoin(ABSENT, PRUNED, PRUNED, DIRTY|FRESH, DIRTY|FRESH);
+ CheckAccessCoin(ABSENT, VALUE2, VALUE2, 0 , 0 );
+ CheckAccessCoin(ABSENT, VALUE2, VALUE2, FRESH , FRESH );
+ CheckAccessCoin(ABSENT, VALUE2, VALUE2, DIRTY , DIRTY );
+ CheckAccessCoin(ABSENT, VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH);
+ CheckAccessCoin(PRUNED, ABSENT, ABSENT, NO_ENTRY , NO_ENTRY );
+ CheckAccessCoin(PRUNED, PRUNED, PRUNED, 0 , 0 );
+ CheckAccessCoin(PRUNED, PRUNED, PRUNED, FRESH , FRESH );
+ CheckAccessCoin(PRUNED, PRUNED, PRUNED, DIRTY , DIRTY );
+ CheckAccessCoin(PRUNED, PRUNED, PRUNED, DIRTY|FRESH, DIRTY|FRESH);
+ CheckAccessCoin(PRUNED, VALUE2, VALUE2, 0 , 0 );
+ CheckAccessCoin(PRUNED, VALUE2, VALUE2, FRESH , FRESH );
+ CheckAccessCoin(PRUNED, VALUE2, VALUE2, DIRTY , DIRTY );
+ CheckAccessCoin(PRUNED, VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH);
+ CheckAccessCoin(VALUE1, ABSENT, VALUE1, NO_ENTRY , 0 );
+ CheckAccessCoin(VALUE1, PRUNED, PRUNED, 0 , 0 );
+ CheckAccessCoin(VALUE1, PRUNED, PRUNED, FRESH , FRESH );
+ CheckAccessCoin(VALUE1, PRUNED, PRUNED, DIRTY , DIRTY );
+ CheckAccessCoin(VALUE1, PRUNED, PRUNED, DIRTY|FRESH, DIRTY|FRESH);
+ CheckAccessCoin(VALUE1, VALUE2, VALUE2, 0 , 0 );
+ CheckAccessCoin(VALUE1, VALUE2, VALUE2, FRESH , FRESH );
+ CheckAccessCoin(VALUE1, VALUE2, VALUE2, DIRTY , DIRTY );
+ CheckAccessCoin(VALUE1, VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH);
}
-void CheckModifyCoins(CAmount base_value, CAmount cache_value, CAmount modify_value, CAmount expected_value, char cache_flags, char expected_flags)
+void CheckSpendCoins(CAmount base_value, CAmount cache_value, CAmount expected_value, char cache_flags, char expected_flags)
{
SingleEntryCacheTest test(base_value, cache_value, cache_flags);
- SetCoinsValue(modify_value, *test.cache.ModifyCoins(TXID));
+ test.cache.SpendCoin(OUTPOINT);
test.cache.SelfTest();
CAmount result_value;
@@ -645,79 +669,55 @@ void CheckModifyCoins(CAmount base_value, CAmount cache_value, CAmount modify_va
BOOST_CHECK_EQUAL(result_flags, expected_flags);
};
-BOOST_AUTO_TEST_CASE(ccoins_modify)
+BOOST_AUTO_TEST_CASE(ccoins_spend)
{
- /* Check ModifyCoin behavior, requesting a coin from a cache view layered on
- * top of a base view, writing a modification to the coin, and then checking
+ /* Check SpendCoin behavior, requesting a coin from a cache view layered on
+ * top of a base view, spending, and then checking
* the resulting entry in the cache after the modification.
*
- * Base Cache Write Result Cache Result
- * Value Value Value Value Flags Flags
+ * Base Cache Result Cache Result
+ * Value Value Value Flags Flags
*/
- CheckModifyCoins(ABSENT, ABSENT, PRUNED, ABSENT, NO_ENTRY , NO_ENTRY );
- CheckModifyCoins(ABSENT, ABSENT, VALUE3, VALUE3, NO_ENTRY , DIRTY|FRESH);
- CheckModifyCoins(ABSENT, PRUNED, PRUNED, PRUNED, 0 , DIRTY );
- CheckModifyCoins(ABSENT, PRUNED, PRUNED, ABSENT, FRESH , NO_ENTRY );
- CheckModifyCoins(ABSENT, PRUNED, PRUNED, PRUNED, DIRTY , DIRTY );
- CheckModifyCoins(ABSENT, PRUNED, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY );
- CheckModifyCoins(ABSENT, PRUNED, VALUE3, VALUE3, 0 , DIRTY );
- CheckModifyCoins(ABSENT, PRUNED, VALUE3, VALUE3, FRESH , DIRTY|FRESH);
- CheckModifyCoins(ABSENT, PRUNED, VALUE3, VALUE3, DIRTY , DIRTY );
- CheckModifyCoins(ABSENT, PRUNED, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH);
- CheckModifyCoins(ABSENT, VALUE2, PRUNED, PRUNED, 0 , DIRTY );
- CheckModifyCoins(ABSENT, VALUE2, PRUNED, ABSENT, FRESH , NO_ENTRY );
- CheckModifyCoins(ABSENT, VALUE2, PRUNED, PRUNED, DIRTY , DIRTY );
- CheckModifyCoins(ABSENT, VALUE2, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY );
- CheckModifyCoins(ABSENT, VALUE2, VALUE3, VALUE3, 0 , DIRTY );
- CheckModifyCoins(ABSENT, VALUE2, VALUE3, VALUE3, FRESH , DIRTY|FRESH);
- CheckModifyCoins(ABSENT, VALUE2, VALUE3, VALUE3, DIRTY , DIRTY );
- CheckModifyCoins(ABSENT, VALUE2, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH);
- CheckModifyCoins(PRUNED, ABSENT, PRUNED, ABSENT, NO_ENTRY , NO_ENTRY );
- CheckModifyCoins(PRUNED, ABSENT, VALUE3, VALUE3, NO_ENTRY , DIRTY|FRESH);
- CheckModifyCoins(PRUNED, PRUNED, PRUNED, PRUNED, 0 , DIRTY );
- CheckModifyCoins(PRUNED, PRUNED, PRUNED, ABSENT, FRESH , NO_ENTRY );
- CheckModifyCoins(PRUNED, PRUNED, PRUNED, PRUNED, DIRTY , DIRTY );
- CheckModifyCoins(PRUNED, PRUNED, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY );
- CheckModifyCoins(PRUNED, PRUNED, VALUE3, VALUE3, 0 , DIRTY );
- CheckModifyCoins(PRUNED, PRUNED, VALUE3, VALUE3, FRESH , DIRTY|FRESH);
- CheckModifyCoins(PRUNED, PRUNED, VALUE3, VALUE3, DIRTY , DIRTY );
- CheckModifyCoins(PRUNED, PRUNED, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH);
- CheckModifyCoins(PRUNED, VALUE2, PRUNED, PRUNED, 0 , DIRTY );
- CheckModifyCoins(PRUNED, VALUE2, PRUNED, ABSENT, FRESH , NO_ENTRY );
- CheckModifyCoins(PRUNED, VALUE2, PRUNED, PRUNED, DIRTY , DIRTY );
- CheckModifyCoins(PRUNED, VALUE2, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY );
- CheckModifyCoins(PRUNED, VALUE2, VALUE3, VALUE3, 0 , DIRTY );
- CheckModifyCoins(PRUNED, VALUE2, VALUE3, VALUE3, FRESH , DIRTY|FRESH);
- CheckModifyCoins(PRUNED, VALUE2, VALUE3, VALUE3, DIRTY , DIRTY );
- CheckModifyCoins(PRUNED, VALUE2, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH);
- CheckModifyCoins(VALUE1, ABSENT, PRUNED, PRUNED, NO_ENTRY , DIRTY );
- CheckModifyCoins(VALUE1, ABSENT, VALUE3, VALUE3, NO_ENTRY , DIRTY );
- CheckModifyCoins(VALUE1, PRUNED, PRUNED, PRUNED, 0 , DIRTY );
- CheckModifyCoins(VALUE1, PRUNED, PRUNED, ABSENT, FRESH , NO_ENTRY );
- CheckModifyCoins(VALUE1, PRUNED, PRUNED, PRUNED, DIRTY , DIRTY );
- CheckModifyCoins(VALUE1, PRUNED, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY );
- CheckModifyCoins(VALUE1, PRUNED, VALUE3, VALUE3, 0 , DIRTY );
- CheckModifyCoins(VALUE1, PRUNED, VALUE3, VALUE3, FRESH , DIRTY|FRESH);
- CheckModifyCoins(VALUE1, PRUNED, VALUE3, VALUE3, DIRTY , DIRTY );
- CheckModifyCoins(VALUE1, PRUNED, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH);
- CheckModifyCoins(VALUE1, VALUE2, PRUNED, PRUNED, 0 , DIRTY );
- CheckModifyCoins(VALUE1, VALUE2, PRUNED, ABSENT, FRESH , NO_ENTRY );
- CheckModifyCoins(VALUE1, VALUE2, PRUNED, PRUNED, DIRTY , DIRTY );
- CheckModifyCoins(VALUE1, VALUE2, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY );
- CheckModifyCoins(VALUE1, VALUE2, VALUE3, VALUE3, 0 , DIRTY );
- CheckModifyCoins(VALUE1, VALUE2, VALUE3, VALUE3, FRESH , DIRTY|FRESH);
- CheckModifyCoins(VALUE1, VALUE2, VALUE3, VALUE3, DIRTY , DIRTY );
- CheckModifyCoins(VALUE1, VALUE2, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH);
+ CheckSpendCoins(ABSENT, ABSENT, ABSENT, NO_ENTRY , NO_ENTRY );
+ CheckSpendCoins(ABSENT, PRUNED, PRUNED, 0 , DIRTY );
+ CheckSpendCoins(ABSENT, PRUNED, ABSENT, FRESH , NO_ENTRY );
+ CheckSpendCoins(ABSENT, PRUNED, PRUNED, DIRTY , DIRTY );
+ CheckSpendCoins(ABSENT, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY );
+ CheckSpendCoins(ABSENT, VALUE2, PRUNED, 0 , DIRTY );
+ CheckSpendCoins(ABSENT, VALUE2, ABSENT, FRESH , NO_ENTRY );
+ CheckSpendCoins(ABSENT, VALUE2, PRUNED, DIRTY , DIRTY );
+ CheckSpendCoins(ABSENT, VALUE2, ABSENT, DIRTY|FRESH, NO_ENTRY );
+ CheckSpendCoins(PRUNED, ABSENT, ABSENT, NO_ENTRY , NO_ENTRY );
+ CheckSpendCoins(PRUNED, PRUNED, PRUNED, 0 , DIRTY );
+ CheckSpendCoins(PRUNED, PRUNED, ABSENT, FRESH , NO_ENTRY );
+ CheckSpendCoins(PRUNED, PRUNED, PRUNED, DIRTY , DIRTY );
+ CheckSpendCoins(PRUNED, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY );
+ CheckSpendCoins(PRUNED, VALUE2, PRUNED, 0 , DIRTY );
+ CheckSpendCoins(PRUNED, VALUE2, ABSENT, FRESH , NO_ENTRY );
+ CheckSpendCoins(PRUNED, VALUE2, PRUNED, DIRTY , DIRTY );
+ CheckSpendCoins(PRUNED, VALUE2, ABSENT, DIRTY|FRESH, NO_ENTRY );
+ CheckSpendCoins(VALUE1, ABSENT, PRUNED, NO_ENTRY , DIRTY );
+ CheckSpendCoins(VALUE1, PRUNED, PRUNED, 0 , DIRTY );
+ CheckSpendCoins(VALUE1, PRUNED, ABSENT, FRESH , NO_ENTRY );
+ CheckSpendCoins(VALUE1, PRUNED, PRUNED, DIRTY , DIRTY );
+ CheckSpendCoins(VALUE1, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY );
+ CheckSpendCoins(VALUE1, VALUE2, PRUNED, 0 , DIRTY );
+ CheckSpendCoins(VALUE1, VALUE2, ABSENT, FRESH , NO_ENTRY );
+ CheckSpendCoins(VALUE1, VALUE2, PRUNED, DIRTY , DIRTY );
+ CheckSpendCoins(VALUE1, VALUE2, ABSENT, DIRTY|FRESH, NO_ENTRY );
}
-void CheckModifyNewCoinsBase(CAmount base_value, CAmount cache_value, CAmount modify_value, CAmount expected_value, char cache_flags, char expected_flags, bool coinbase)
+void CheckAddCoinBase(CAmount base_value, CAmount cache_value, CAmount modify_value, CAmount expected_value, char cache_flags, char expected_flags, bool coinbase)
{
SingleEntryCacheTest test(base_value, cache_value, cache_flags);
CAmount result_value;
char result_flags;
try {
- SetCoinsValue(modify_value, *test.cache.ModifyNewCoins(TXID, coinbase));
+ CTxOut output;
+ output.nValue = modify_value;
+ test.cache.AddCoin(OUTPOINT, Coin(std::move(output), 1, coinbase), coinbase);
+ test.cache.SelfTest();
GetCoinsMapEntry(test.cache.map(), result_value, result_flags);
} catch (std::logic_error& e) {
result_value = FAIL;
@@ -728,64 +728,46 @@ void CheckModifyNewCoinsBase(CAmount base_value, CAmount cache_value, CAmount mo
BOOST_CHECK_EQUAL(result_flags, expected_flags);
}
-// Simple wrapper for CheckModifyNewCoinsBase function above that loops through
+// Simple wrapper for CheckAddCoinBase function above that loops through
// different possible base_values, making sure each one gives the same results.
-// This wrapper lets the modify_new test below be shorter and less repetitive,
-// while still verifying that the CoinsViewCache::ModifyNewCoins implementation
+// This wrapper lets the coins_add test below be shorter and less repetitive,
+// while still verifying that the CoinsViewCache::AddCoin implementation
// ignores base values.
template <typename... Args>
-void CheckModifyNewCoins(Args&&... args)
+void CheckAddCoin(Args&&... args)
{
for (CAmount base_value : {ABSENT, PRUNED, VALUE1})
- CheckModifyNewCoinsBase(base_value, std::forward<Args>(args)...);
+ CheckAddCoinBase(base_value, std::forward<Args>(args)...);
}
-BOOST_AUTO_TEST_CASE(ccoins_modify_new)
+BOOST_AUTO_TEST_CASE(ccoins_add)
{
- /* Check ModifyNewCoin behavior, requesting a new coin from a cache view,
+ /* Check AddCoin behavior, requesting a new coin from a cache view,
* writing a modification to the coin, and then checking the resulting
* entry in the cache after the modification. Verify behavior with the
- * with the ModifyNewCoin coinbase argument set to false, and to true.
+ * with the AddCoin potential_overwrite argument set to false, and to true.
*
- * Cache Write Result Cache Result Coinbase
- * Value Value Value Flags Flags
+ * Cache Write Result Cache Result potential_overwrite
+ * Value Value Value Flags Flags
*/
- CheckModifyNewCoins(ABSENT, PRUNED, ABSENT, NO_ENTRY , NO_ENTRY , false);
- CheckModifyNewCoins(ABSENT, PRUNED, PRUNED, NO_ENTRY , DIRTY , true );
- CheckModifyNewCoins(ABSENT, VALUE3, VALUE3, NO_ENTRY , DIRTY|FRESH, false);
- CheckModifyNewCoins(ABSENT, VALUE3, VALUE3, NO_ENTRY , DIRTY , true );
- CheckModifyNewCoins(PRUNED, PRUNED, ABSENT, 0 , NO_ENTRY , false);
- CheckModifyNewCoins(PRUNED, PRUNED, PRUNED, 0 , DIRTY , true );
- CheckModifyNewCoins(PRUNED, PRUNED, ABSENT, FRESH , NO_ENTRY , false);
- CheckModifyNewCoins(PRUNED, PRUNED, ABSENT, FRESH , NO_ENTRY , true );
- CheckModifyNewCoins(PRUNED, PRUNED, PRUNED, DIRTY , DIRTY , false);
- CheckModifyNewCoins(PRUNED, PRUNED, PRUNED, DIRTY , DIRTY , true );
- CheckModifyNewCoins(PRUNED, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY , false);
- CheckModifyNewCoins(PRUNED, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY , true );
- CheckModifyNewCoins(PRUNED, VALUE3, VALUE3, 0 , DIRTY|FRESH, false);
- CheckModifyNewCoins(PRUNED, VALUE3, VALUE3, 0 , DIRTY , true );
- CheckModifyNewCoins(PRUNED, VALUE3, VALUE3, FRESH , DIRTY|FRESH, false);
- CheckModifyNewCoins(PRUNED, VALUE3, VALUE3, FRESH , DIRTY|FRESH, true );
- CheckModifyNewCoins(PRUNED, VALUE3, VALUE3, DIRTY , DIRTY , false);
- CheckModifyNewCoins(PRUNED, VALUE3, VALUE3, DIRTY , DIRTY , true );
- CheckModifyNewCoins(PRUNED, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, false);
- CheckModifyNewCoins(PRUNED, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, true );
- CheckModifyNewCoins(VALUE2, PRUNED, FAIL , 0 , NO_ENTRY , false);
- CheckModifyNewCoins(VALUE2, PRUNED, PRUNED, 0 , DIRTY , true );
- CheckModifyNewCoins(VALUE2, PRUNED, FAIL , FRESH , NO_ENTRY , false);
- CheckModifyNewCoins(VALUE2, PRUNED, ABSENT, FRESH , NO_ENTRY , true );
- CheckModifyNewCoins(VALUE2, PRUNED, FAIL , DIRTY , NO_ENTRY , false);
- CheckModifyNewCoins(VALUE2, PRUNED, PRUNED, DIRTY , DIRTY , true );
- CheckModifyNewCoins(VALUE2, PRUNED, FAIL , DIRTY|FRESH, NO_ENTRY , false);
- CheckModifyNewCoins(VALUE2, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY , true );
- CheckModifyNewCoins(VALUE2, VALUE3, FAIL , 0 , NO_ENTRY , false);
- CheckModifyNewCoins(VALUE2, VALUE3, VALUE3, 0 , DIRTY , true );
- CheckModifyNewCoins(VALUE2, VALUE3, FAIL , FRESH , NO_ENTRY , false);
- CheckModifyNewCoins(VALUE2, VALUE3, VALUE3, FRESH , DIRTY|FRESH, true );
- CheckModifyNewCoins(VALUE2, VALUE3, FAIL , DIRTY , NO_ENTRY , false);
- CheckModifyNewCoins(VALUE2, VALUE3, VALUE3, DIRTY , DIRTY , true );
- CheckModifyNewCoins(VALUE2, VALUE3, FAIL , DIRTY|FRESH, NO_ENTRY , false);
- CheckModifyNewCoins(VALUE2, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, true );
+ CheckAddCoin(ABSENT, VALUE3, VALUE3, NO_ENTRY , DIRTY|FRESH, false);
+ CheckAddCoin(ABSENT, VALUE3, VALUE3, NO_ENTRY , DIRTY , true );
+ CheckAddCoin(PRUNED, VALUE3, VALUE3, 0 , DIRTY|FRESH, false);
+ CheckAddCoin(PRUNED, VALUE3, VALUE3, 0 , DIRTY , true );
+ CheckAddCoin(PRUNED, VALUE3, VALUE3, FRESH , DIRTY|FRESH, false);
+ CheckAddCoin(PRUNED, VALUE3, VALUE3, FRESH , DIRTY|FRESH, true );
+ CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY , DIRTY , false);
+ CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY , DIRTY , true );
+ CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, false);
+ CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, true );
+ CheckAddCoin(VALUE2, VALUE3, FAIL , 0 , NO_ENTRY , false);
+ CheckAddCoin(VALUE2, VALUE3, VALUE3, 0 , DIRTY , true );
+ CheckAddCoin(VALUE2, VALUE3, FAIL , FRESH , NO_ENTRY , false);
+ CheckAddCoin(VALUE2, VALUE3, VALUE3, FRESH , DIRTY|FRESH, true );
+ CheckAddCoin(VALUE2, VALUE3, FAIL , DIRTY , NO_ENTRY , false);
+ CheckAddCoin(VALUE2, VALUE3, VALUE3, DIRTY , DIRTY , true );
+ CheckAddCoin(VALUE2, VALUE3, FAIL , DIRTY|FRESH, NO_ENTRY , false);
+ CheckAddCoin(VALUE2, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, true );
}
void CheckWriteCoins(CAmount parent_value, CAmount child_value, CAmount expected_value, char parent_flags, char child_flags, char expected_flags)
diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp
index 4d17417179..c748b2448c 100644
--- a/src/test/crypto_tests.cpp
+++ b/src/test/crypto_tests.cpp
@@ -3,19 +3,19 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "crypto/aes.h"
+#include "crypto/chacha20.h"
#include "crypto/ripemd160.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
#include "crypto/sha512.h"
#include "crypto/hmac_sha256.h"
#include "crypto/hmac_sha512.h"
+#include "random.h"
#include "utilstrencodings.h"
#include "test/test_bitcoin.h"
-#include "test/test_random.h"
#include <vector>
-#include <boost/assign/list_of.hpp>
#include <boost/test/unit_test.hpp>
#include <openssl/aes.h>
#include <openssl/evp.h>
@@ -37,7 +37,7 @@ void TestVector(const Hasher &h, const In &in, const Out &out) {
Hasher hasher(h);
size_t pos = 0;
while (pos < in.size()) {
- size_t len = insecure_rand() % ((in.size() - pos + 1) / 2 + 1);
+ size_t len = InsecureRandRange((in.size() - pos + 1) / 2 + 1);
hasher.Write((unsigned char*)&in[pos], len);
pos += len;
if (pos > 0 && pos + 2 * out.size() > in.size() && pos < in.size()) {
@@ -58,12 +58,12 @@ void TestRIPEMD160(const std::string &in, const std::string &hexout) { TestVecto
void TestHMACSHA256(const std::string &hexkey, const std::string &hexin, const std::string &hexout) {
std::vector<unsigned char> key = ParseHex(hexkey);
- TestVector(CHMAC_SHA256(&key[0], key.size()), ParseHex(hexin), ParseHex(hexout));
+ TestVector(CHMAC_SHA256(key.data(), key.size()), ParseHex(hexin), ParseHex(hexout));
}
void TestHMACSHA512(const std::string &hexkey, const std::string &hexin, const std::string &hexout) {
std::vector<unsigned char> key = ParseHex(hexkey);
- TestVector(CHMAC_SHA512(&key[0], key.size()), ParseHex(hexin), ParseHex(hexout));
+ TestVector(CHMAC_SHA512(key.data(), key.size()), ParseHex(hexin), ParseHex(hexout));
}
void TestAES128(const std::string &hexkey, const std::string &hexin, const std::string &hexout)
@@ -76,13 +76,13 @@ void TestAES128(const std::string &hexkey, const std::string &hexin, const std::
assert(key.size() == 16);
assert(in.size() == 16);
assert(correctout.size() == 16);
- AES128Encrypt enc(&key[0]);
+ AES128Encrypt enc(key.data());
buf.resize(correctout.size());
buf2.resize(correctout.size());
- enc.Encrypt(&buf[0], &in[0]);
+ enc.Encrypt(buf.data(), in.data());
BOOST_CHECK_EQUAL(HexStr(buf), HexStr(correctout));
- AES128Decrypt dec(&key[0]);
- dec.Decrypt(&buf2[0], &buf[0]);
+ AES128Decrypt dec(key.data());
+ dec.Decrypt(buf2.data(), buf.data());
BOOST_CHECK_EQUAL(HexStr(buf2), HexStr(in));
}
@@ -96,12 +96,12 @@ void TestAES256(const std::string &hexkey, const std::string &hexin, const std::
assert(key.size() == 32);
assert(in.size() == 16);
assert(correctout.size() == 16);
- AES256Encrypt enc(&key[0]);
+ AES256Encrypt enc(key.data());
buf.resize(correctout.size());
- enc.Encrypt(&buf[0], &in[0]);
+ enc.Encrypt(buf.data(), in.data());
BOOST_CHECK(buf == correctout);
- AES256Decrypt dec(&key[0]);
- dec.Decrypt(&buf[0], &buf[0]);
+ AES256Decrypt dec(key.data());
+ dec.Decrypt(buf.data(), buf.data());
BOOST_CHECK(buf == in);
}
@@ -114,16 +114,16 @@ void TestAES128CBC(const std::string &hexkey, const std::string &hexiv, bool pad
std::vector<unsigned char> realout(in.size() + AES_BLOCKSIZE);
// Encrypt the plaintext and verify that it equals the cipher
- AES128CBCEncrypt enc(&key[0], &iv[0], pad);
- int size = enc.Encrypt(&in[0], in.size(), &realout[0]);
+ AES128CBCEncrypt enc(key.data(), iv.data(), pad);
+ int size = enc.Encrypt(in.data(), in.size(), realout.data());
realout.resize(size);
BOOST_CHECK(realout.size() == correctout.size());
BOOST_CHECK_MESSAGE(realout == correctout, HexStr(realout) + std::string(" != ") + hexout);
// Decrypt the cipher and verify that it equals the plaintext
std::vector<unsigned char> decrypted(correctout.size());
- AES128CBCDecrypt dec(&key[0], &iv[0], pad);
- size = dec.Decrypt(&correctout[0], correctout.size(), &decrypted[0]);
+ AES128CBCDecrypt dec(key.data(), iv.data(), pad);
+ size = dec.Decrypt(correctout.data(), correctout.size(), decrypted.data());
decrypted.resize(size);
BOOST_CHECK(decrypted.size() == in.size());
BOOST_CHECK_MESSAGE(decrypted == in, HexStr(decrypted) + std::string(" != ") + hexin);
@@ -133,12 +133,12 @@ void TestAES128CBC(const std::string &hexkey, const std::string &hexiv, bool pad
{
std::vector<unsigned char> sub(i, in.end());
std::vector<unsigned char> subout(sub.size() + AES_BLOCKSIZE);
- int _size = enc.Encrypt(&sub[0], sub.size(), &subout[0]);
+ int _size = enc.Encrypt(sub.data(), sub.size(), subout.data());
if (_size != 0)
{
subout.resize(_size);
std::vector<unsigned char> subdecrypted(subout.size());
- _size = dec.Decrypt(&subout[0], subout.size(), &subdecrypted[0]);
+ _size = dec.Decrypt(subout.data(), subout.size(), subdecrypted.data());
subdecrypted.resize(_size);
BOOST_CHECK(decrypted.size() == in.size());
BOOST_CHECK_MESSAGE(subdecrypted == sub, HexStr(subdecrypted) + std::string(" != ") + HexStr(sub));
@@ -155,16 +155,16 @@ void TestAES256CBC(const std::string &hexkey, const std::string &hexiv, bool pad
std::vector<unsigned char> realout(in.size() + AES_BLOCKSIZE);
// Encrypt the plaintext and verify that it equals the cipher
- AES256CBCEncrypt enc(&key[0], &iv[0], pad);
- int size = enc.Encrypt(&in[0], in.size(), &realout[0]);
+ AES256CBCEncrypt enc(key.data(), iv.data(), pad);
+ int size = enc.Encrypt(in.data(), in.size(), realout.data());
realout.resize(size);
BOOST_CHECK(realout.size() == correctout.size());
BOOST_CHECK_MESSAGE(realout == correctout, HexStr(realout) + std::string(" != ") + hexout);
// Decrypt the cipher and verify that it equals the plaintext
std::vector<unsigned char> decrypted(correctout.size());
- AES256CBCDecrypt dec(&key[0], &iv[0], pad);
- size = dec.Decrypt(&correctout[0], correctout.size(), &decrypted[0]);
+ AES256CBCDecrypt dec(key.data(), iv.data(), pad);
+ size = dec.Decrypt(correctout.data(), correctout.size(), decrypted.data());
decrypted.resize(size);
BOOST_CHECK(decrypted.size() == in.size());
BOOST_CHECK_MESSAGE(decrypted == in, HexStr(decrypted) + std::string(" != ") + hexin);
@@ -174,12 +174,12 @@ void TestAES256CBC(const std::string &hexkey, const std::string &hexiv, bool pad
{
std::vector<unsigned char> sub(i, in.end());
std::vector<unsigned char> subout(sub.size() + AES_BLOCKSIZE);
- int _size = enc.Encrypt(&sub[0], sub.size(), &subout[0]);
+ int _size = enc.Encrypt(sub.data(), sub.size(), subout.data());
if (_size != 0)
{
subout.resize(_size);
std::vector<unsigned char> subdecrypted(subout.size());
- _size = dec.Decrypt(&subout[0], subout.size(), &subdecrypted[0]);
+ _size = dec.Decrypt(subout.data(), subout.size(), subdecrypted.data());
subdecrypted.resize(_size);
BOOST_CHECK(decrypted.size() == in.size());
BOOST_CHECK_MESSAGE(subdecrypted == sub, HexStr(subdecrypted) + std::string(" != ") + HexStr(sub));
@@ -187,6 +187,19 @@ void TestAES256CBC(const std::string &hexkey, const std::string &hexiv, bool pad
}
}
+void TestChaCha20(const std::string &hexkey, uint64_t nonce, uint64_t seek, const std::string& hexout)
+{
+ std::vector<unsigned char> key = ParseHex(hexkey);
+ ChaCha20 rng(key.data(), key.size());
+ rng.SetIV(nonce);
+ rng.Seek(seek);
+ std::vector<unsigned char> out = ParseHex(hexout);
+ std::vector<unsigned char> outres;
+ outres.resize(out.size());
+ rng.Output(outres.data(), outres.size());
+ BOOST_CHECK(out == outres);
+}
+
std::string LongTestString(void) {
std::string ret;
for (int i=0; i<200000; i++) {
@@ -439,4 +452,57 @@ BOOST_AUTO_TEST_CASE(aes_cbc_testvectors) {
"b2eb05e2c39be9fcda6c19078c6a9d1b3f461796d6b0d6b2e0c2a72b4d80e644");
}
+
+BOOST_AUTO_TEST_CASE(chacha20_testvector)
+{
+ // Test vector from RFC 7539
+ TestChaCha20("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0x4a000000UL, 1,
+ "224f51f3401bd9e12fde276fb8631ded8c131f823d2c06e27e4fcaec9ef3cf788a3b0aa372600a92b57974cded2b9334794cb"
+ "a40c63e34cdea212c4cf07d41b769a6749f3f630f4122cafe28ec4dc47e26d4346d70b98c73f3e9c53ac40c5945398b6eda1a"
+ "832c89c167eacd901d7e2bf363");
+
+ // Test vectors from https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#section-7
+ TestChaCha20("0000000000000000000000000000000000000000000000000000000000000000", 0, 0,
+ "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b"
+ "8f41518a11cc387b669b2ee6586");
+ TestChaCha20("0000000000000000000000000000000000000000000000000000000000000001", 0, 0,
+ "4540f05a9f1fb296d7736e7b208e3c96eb4fe1834688d2604f450952ed432d41bbe2a0b6ea7566d2a5d1e7e20d42af2c53d79"
+ "2b1c43fea817e9ad275ae546963");
+ TestChaCha20("0000000000000000000000000000000000000000000000000000000000000000", 0x0100000000000000ULL, 0,
+ "de9cba7bf3d69ef5e786dc63973f653a0b49e015adbff7134fcb7df137821031e85a050278a7084527214f73efc7fa5b52770"
+ "62eb7a0433e445f41e3");
+ TestChaCha20("0000000000000000000000000000000000000000000000000000000000000000", 1, 0,
+ "ef3fdfd6c61578fbf5cf35bd3dd33b8009631634d21e42ac33960bd138e50d32111e4caf237ee53ca8ad6426194a88545ddc4"
+ "97a0b466e7d6bbdb0041b2f586b");
+ TestChaCha20("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0x0706050403020100ULL, 0,
+ "f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c9440049176905d3b"
+ "e59ea1c53f15916155c2be8241a38008b9a26bc35941e2444177c8ade6689de95264986d95889fb60e84629c9bd9a5acb1cc1"
+ "18be563eb9b3a4a472f82e09a7e778492b562ef7130e88dfe031c79db9d4f7c7a899151b9a475032b63fc385245fe054e3dd5"
+ "a97a5f576fe064025d3ce042c566ab2c507b138db853e3d6959660996546cc9c4a6eafdc777c040d70eaf46f76dad3979e5c5"
+ "360c3317166a1c894c94a371876a94df7628fe4eaaf2ccb27d5aaae0ad7ad0f9d4b6ad3b54098746d4524d38407a6deb3ab78"
+ "fab78c9");
+}
+
+BOOST_AUTO_TEST_CASE(countbits_tests)
+{
+ FastRandomContext ctx;
+ for (int i = 0; i <= 64; ++i) {
+ if (i == 0) {
+ // Check handling of zero.
+ BOOST_CHECK_EQUAL(CountBits(0), 0);
+ } else if (i < 10) {
+ for (uint64_t j = 1 << (i - 1); (j >> i) == 0; ++j) {
+ // Exhaustively test up to 10 bits
+ BOOST_CHECK_EQUAL(CountBits(j), i);
+ }
+ } else {
+ for (int k = 0; k < 1000; k++) {
+ // Randomly test 1000 samples of each length above 10 bits.
+ uint64_t j = ((uint64_t)1) << (i - 1) | ctx.randbits(i - 1);
+ BOOST_CHECK_EQUAL(CountBits(j), i);
+ }
+ }
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/cuckoocache_tests.cpp b/src/test/cuckoocache_tests.cpp
index 1bc50d5ea9..1004482224 100644
--- a/src/test/cuckoocache_tests.cpp
+++ b/src/test/cuckoocache_tests.cpp
@@ -3,11 +3,10 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <boost/test/unit_test.hpp>
#include "cuckoocache.h"
+#include "script/sigcache.h"
#include "test/test_bitcoin.h"
#include "random.h"
#include <thread>
-#include <boost/thread.hpp>
-
/** Test Suite for CuckooCache
*
@@ -15,41 +14,27 @@
* with deterministic seeds)
* 2) Some test methods are templated to allow for easier testing
* against new versions / comparing
- * 3) Results should be treated as a regression test, ie, did the behavior
+ * 3) Results should be treated as a regression test, i.e., did the behavior
* change significantly from what was expected. This can be OK, depending on
* the nature of the change, but requires updating the tests to reflect the new
* expected behavior. For example improving the hit rate may cause some tests
* using BOOST_CHECK_CLOSE to fail.
*
*/
-FastRandomContext insecure_rand(true);
+FastRandomContext local_rand_ctx(true);
BOOST_AUTO_TEST_SUITE(cuckoocache_tests);
-/** insecure_GetRandHash fills in a uint256 from insecure_rand
+/** insecure_GetRandHash fills in a uint256 from local_rand_ctx
*/
void insecure_GetRandHash(uint256& t)
{
uint32_t* ptr = (uint32_t*)t.begin();
for (uint8_t j = 0; j < 8; ++j)
- *(ptr++) = insecure_rand.rand32();
+ *(ptr++) = local_rand_ctx.rand32();
}
-/** Definition copied from /src/script/sigcache.cpp
- */
-class uint256Hasher
-{
-public:
- template <uint8_t hash_select>
- uint32_t operator()(const uint256& key) const
- {
- static_assert(hash_select <8, "SignatureCacheHasher only has 8 hashes available.");
- uint32_t u;
- std::memcpy(&u, key.begin() + 4 * hash_select, 4);
- return u;
- }
-};
/* Test that no values not inserted into the cache are read out of it.
@@ -58,9 +43,10 @@ public:
*/
BOOST_AUTO_TEST_CASE(test_cuckoocache_no_fakes)
{
- insecure_rand = FastRandomContext(true);
- CuckooCache::cache<uint256, uint256Hasher> cc{};
- cc.setup_bytes(32 << 20);
+ local_rand_ctx = FastRandomContext(true);
+ CuckooCache::cache<uint256, SignatureCacheHasher> cc{};
+ size_t megabytes = 4;
+ cc.setup_bytes(megabytes << 20);
uint256 v;
for (int x = 0; x < 100000; ++x) {
insecure_GetRandHash(v);
@@ -78,7 +64,7 @@ BOOST_AUTO_TEST_CASE(test_cuckoocache_no_fakes)
template <typename Cache>
double test_cache(size_t megabytes, double load)
{
- insecure_rand = FastRandomContext(true);
+ local_rand_ctx = FastRandomContext(true);
std::vector<uint256> hashes;
Cache set{};
size_t bytes = megabytes * (1 << 20);
@@ -88,7 +74,7 @@ double test_cache(size_t megabytes, double load)
for (uint32_t i = 0; i < n_insert; ++i) {
uint32_t* ptr = (uint32_t*)hashes[i].begin();
for (uint8_t j = 0; j < 8; ++j)
- *(ptr++) = insecure_rand.rand32();
+ *(ptr++) = local_rand_ctx.rand32();
}
/** We make a copy of the hashes because future optimizations of the
* cuckoocache may overwrite the inserted element, so the test is
@@ -135,9 +121,9 @@ BOOST_AUTO_TEST_CASE(cuckoocache_hit_rate_ok)
* as a lower bound on performance.
*/
double HitRateThresh = 0.98;
- size_t megabytes = 32;
+ size_t megabytes = 4;
for (double load = 0.1; load < 2; load *= 2) {
- double hits = test_cache<CuckooCache::cache<uint256, uint256Hasher>>(megabytes, load);
+ double hits = test_cache<CuckooCache::cache<uint256, SignatureCacheHasher>>(megabytes, load);
BOOST_CHECK(normalize_hit_rate(hits, load) > HitRateThresh);
}
}
@@ -149,7 +135,7 @@ template <typename Cache>
void test_cache_erase(size_t megabytes)
{
double load = 1;
- insecure_rand = FastRandomContext(true);
+ local_rand_ctx = FastRandomContext(true);
std::vector<uint256> hashes;
Cache set{};
size_t bytes = megabytes * (1 << 20);
@@ -159,7 +145,7 @@ void test_cache_erase(size_t megabytes)
for (uint32_t i = 0; i < n_insert; ++i) {
uint32_t* ptr = (uint32_t*)hashes[i].begin();
for (uint8_t j = 0; j < 8; ++j)
- *(ptr++) = insecure_rand.rand32();
+ *(ptr++) = local_rand_ctx.rand32();
}
/** We make a copy of the hashes because future optimizations of the
* cuckoocache may overwrite the inserted element, so the test is
@@ -204,15 +190,15 @@ void test_cache_erase(size_t megabytes)
BOOST_AUTO_TEST_CASE(cuckoocache_erase_ok)
{
- size_t megabytes = 32;
- test_cache_erase<CuckooCache::cache<uint256, uint256Hasher>>(megabytes);
+ size_t megabytes = 4;
+ test_cache_erase<CuckooCache::cache<uint256, SignatureCacheHasher>>(megabytes);
}
template <typename Cache>
void test_cache_erase_parallel(size_t megabytes)
{
double load = 1;
- insecure_rand = FastRandomContext(true);
+ local_rand_ctx = FastRandomContext(true);
std::vector<uint256> hashes;
Cache set{};
size_t bytes = megabytes * (1 << 20);
@@ -222,7 +208,7 @@ void test_cache_erase_parallel(size_t megabytes)
for (uint32_t i = 0; i < n_insert; ++i) {
uint32_t* ptr = (uint32_t*)hashes[i].begin();
for (uint8_t j = 0; j < 8; ++j)
- *(ptr++) = insecure_rand.rand32();
+ *(ptr++) = local_rand_ctx.rand32();
}
/** We make a copy of the hashes because future optimizations of the
* cuckoocache may overwrite the inserted element, so the test is
@@ -291,8 +277,8 @@ void test_cache_erase_parallel(size_t megabytes)
}
BOOST_AUTO_TEST_CASE(cuckoocache_erase_parallel_ok)
{
- size_t megabytes = 32;
- test_cache_erase_parallel<CuckooCache::cache<uint256, uint256Hasher>>(megabytes);
+ size_t megabytes = 4;
+ test_cache_erase_parallel<CuckooCache::cache<uint256, SignatureCacheHasher>>(megabytes);
}
@@ -314,7 +300,7 @@ void test_cache_generations()
// iterations with non-deterministic values, so it isn't "overfit" to the
// specific entropy in FastRandomContext(true) and implementation of the
// cache.
- insecure_rand = FastRandomContext(true);
+ local_rand_ctx = FastRandomContext(true);
// block_activity models a chunk of network activity. n_insert elements are
// adde to the cache. The first and last n/4 are stored for removal later
@@ -331,7 +317,7 @@ void test_cache_generations()
for (uint32_t i = 0; i < n_insert; ++i) {
uint32_t* ptr = (uint32_t*)inserts[i].begin();
for (uint8_t j = 0; j < 8; ++j)
- *(ptr++) = insecure_rand.rand32();
+ *(ptr++) = local_rand_ctx.rand32();
}
for (uint32_t i = 0; i < n_insert / 4; ++i)
reads.push_back(inserts[i]);
@@ -342,13 +328,13 @@ void test_cache_generations()
}
};
- const uint32_t BLOCK_SIZE = 10000;
+ const uint32_t BLOCK_SIZE = 1000;
// We expect window size 60 to perform reasonably given that each epoch
// stores 45% of the cache size (~472k).
const uint32_t WINDOW_SIZE = 60;
const uint32_t POP_AMOUNT = (BLOCK_SIZE / WINDOW_SIZE) / 2;
const double load = 10;
- const size_t megabytes = 32;
+ const size_t megabytes = 4;
const size_t bytes = megabytes * (1 << 20);
const uint32_t n_insert = static_cast<uint32_t>(load * (bytes / sizeof(uint256)));
@@ -379,7 +365,7 @@ void test_cache_generations()
// Loose Check that hit rate is above min_hit_rate
BOOST_CHECK(hit > min_hit_rate);
// Tighter check, count number of times we are less than tight_hit_rate
- // (and implicityly, greater than min_hit_rate)
+ // (and implicitly, greater than min_hit_rate)
out_of_tight_tolerance += hit < tight_hit_rate;
}
// Check that being out of tolerance happens less than
@@ -388,7 +374,7 @@ void test_cache_generations()
}
BOOST_AUTO_TEST_CASE(cuckoocache_generations)
{
- test_cache_generations<CuckooCache::cache<uint256, uint256Hasher>>();
+ test_cache_generations<CuckooCache::cache<uint256, SignatureCacheHasher>>();
}
BOOST_AUTO_TEST_SUITE_END();
diff --git a/src/test/data/base58_keys_invalid.json b/src/test/data/base58_keys_invalid.json
index a088620f1b..2056c7491c 100644
--- a/src/test/data/base58_keys_invalid.json
+++ b/src/test/data/base58_keys_invalid.json
@@ -148,5 +148,35 @@
],
[
"2A1q1YsMZowabbvta7kTy2Fd6qN4r5ZCeG3qLpvZBMzCixMUdkN2Y4dHB1wPsZAeVXUGD83MfRED"
+ ],
+ [
+ "tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty"
+ ],
+ [
+ "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5"
+ ],
+ [
+ "BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2"
+ ],
+ [
+ "bc1rw5uspcuh"
+ ],
+ [
+ "bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90"
+ ],
+ [
+ "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P"
+ ],
+ [
+ "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7"
+ ],
+ [
+ "bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du"
+ ],
+ [
+ "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv"
+ ],
+ [
+ "bc1gmk9yu"
]
]
diff --git a/src/test/data/base58_keys_valid.json b/src/test/data/base58_keys_valid.json
index e1e252e22d..8418a6002d 100644
--- a/src/test/data/base58_keys_valid.json
+++ b/src/test/data/base58_keys_valid.json
@@ -1,452 +1,533 @@
[
[
- "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",
- "65a16059864a2fdbc7c99a4723a8395bc6f188eb",
+ "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",
+ "76a91465a16059864a2fdbc7c99a4723a8395bc6f188eb88ac",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "main"
}
- ],
+ ],
[
- "3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou",
- "74f209f6ea907e2ea48f74fae05782ae8a665257",
+ "3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou",
+ "a91474f209f6ea907e2ea48f74fae05782ae8a66525787",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "main"
}
- ],
+ ],
[
- "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs",
- "53c0307d6851aa0ce7825ba883c6bd9ad242b486",
+ "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs",
+ "76a91453c0307d6851aa0ce7825ba883c6bd9ad242b48688ac",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": true
+ "isPrivkey": false,
+ "chain": "test"
}
- ],
+ ],
[
- "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br",
- "6349a418fc4578d10a372b54b45c280cc8c4382f",
+ "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs",
+ "76a91453c0307d6851aa0ce7825ba883c6bd9ad242b48688ac",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": true
+ "isPrivkey": false,
+ "chain": "regtest"
}
- ],
+ ],
[
- "5Kd3NBUAdUnhyzenEwVLy9pBKxSwXvE9FMPyR4UKZvpe6E3AgLr",
- "eddbdc1168f1daeadbd3e44c1e3f8f5a284c2029f78ad26af98583a499de5b19",
+ "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br",
+ "a9146349a418fc4578d10a372b54b45c280cc8c4382f87",
{
- "isCompressed": false,
- "isPrivkey": true,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "test"
}
- ],
+ ],
[
- "Kz6UJmQACJmLtaQj5A3JAge4kVTNQ8gbvXuwbmCj7bsaabudb3RD",
- "55c9bccb9ed68446d1b75273bbce89d7fe013a8acd1625514420fb2aca1a21c4",
+ "5Kd3NBUAdUnhyzenEwVLy9pBKxSwXvE9FMPyR4UKZvpe6E3AgLr",
+ "eddbdc1168f1daeadbd3e44c1e3f8f5a284c2029f78ad26af98583a499de5b19",
{
- "isCompressed": true,
- "isPrivkey": true,
- "isTestnet": false
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "main"
}
- ],
+ ],
[
- "9213qJab2HNEpMpYNBa7wHGFKKbkDn24jpANDs2huN3yi4J11ko",
- "36cb93b9ab1bdabf7fb9f2c04f1b9cc879933530ae7842398eef5a63a56800c2",
+ "Kz6UJmQACJmLtaQj5A3JAge4kVTNQ8gbvXuwbmCj7bsaabudb3RD",
+ "55c9bccb9ed68446d1b75273bbce89d7fe013a8acd1625514420fb2aca1a21c4",
{
- "isCompressed": false,
- "isPrivkey": true,
- "isTestnet": true
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "main"
}
- ],
+ ],
[
- "cTpB4YiyKiBcPxnefsDpbnDxFDffjqJob8wGCEDXxgQ7zQoMXJdH",
- "b9f4892c9e8282028fea1d2667c4dc5213564d41fc5783896a0d843fc15089f3",
+ "9213qJab2HNEpMpYNBa7wHGFKKbkDn24jpANDs2huN3yi4J11ko",
+ "36cb93b9ab1bdabf7fb9f2c04f1b9cc879933530ae7842398eef5a63a56800c2",
{
- "isCompressed": true,
- "isPrivkey": true,
- "isTestnet": true
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "test"
}
- ],
+ ],
[
- "1Ax4gZtb7gAit2TivwejZHYtNNLT18PUXJ",
- "6d23156cbbdcc82a5a47eee4c2c7c583c18b6bf4",
+ "9213qJab2HNEpMpYNBa7wHGFKKbkDn24jpANDs2huN3yi4J11ko",
+ "36cb93b9ab1bdabf7fb9f2c04f1b9cc879933530ae7842398eef5a63a56800c2",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": false
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "regtest"
}
- ],
+ ],
[
- "3QjYXhTkvuj8qPaXHTTWb5wjXhdsLAAWVy",
- "fcc5460dd6e2487c7d75b1963625da0e8f4c5975",
+ "cTpB4YiyKiBcPxnefsDpbnDxFDffjqJob8wGCEDXxgQ7zQoMXJdH",
+ "b9f4892c9e8282028fea1d2667c4dc5213564d41fc5783896a0d843fc15089f3",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": false
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "test"
}
- ],
+ ],
[
- "n3ZddxzLvAY9o7184TB4c6FJasAybsw4HZ",
- "f1d470f9b02370fdec2e6b708b08ac431bf7a5f7",
+ "cTpB4YiyKiBcPxnefsDpbnDxFDffjqJob8wGCEDXxgQ7zQoMXJdH",
+ "b9f4892c9e8282028fea1d2667c4dc5213564d41fc5783896a0d843fc15089f3",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": true
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "regtest"
}
- ],
+ ],
[
- "2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n",
- "c579342c2c4c9220205e2cdc285617040c924a0a",
+ "1Ax4gZtb7gAit2TivwejZHYtNNLT18PUXJ",
+ "76a9146d23156cbbdcc82a5a47eee4c2c7c583c18b6bf488ac",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": true
+ "isPrivkey": false,
+ "chain": "main"
}
- ],
+ ],
[
- "5K494XZwps2bGyeL71pWid4noiSNA2cfCibrvRWqcHSptoFn7rc",
- "a326b95ebae30164217d7a7f57d72ab2b54e3be64928a19da0210b9568d4015e",
+ "3QjYXhTkvuj8qPaXHTTWb5wjXhdsLAAWVy",
+ "a914fcc5460dd6e2487c7d75b1963625da0e8f4c597587",
{
- "isCompressed": false,
- "isPrivkey": true,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "main"
}
- ],
+ ],
[
- "L1RrrnXkcKut5DEMwtDthjwRcTTwED36thyL1DebVrKuwvohjMNi",
- "7d998b45c219a1e38e99e7cbd312ef67f77a455a9b50c730c27f02c6f730dfb4",
+ "n3ZddxzLvAY9o7184TB4c6FJasAybsw4HZ",
+ "76a914f1d470f9b02370fdec2e6b708b08ac431bf7a5f788ac",
{
- "isCompressed": true,
- "isPrivkey": true,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "test"
}
- ],
+ ],
[
- "93DVKyFYwSN6wEo3E2fCrFPUp17FtrtNi2Lf7n4G3garFb16CRj",
- "d6bca256b5abc5602ec2e1c121a08b0da2556587430bcf7e1898af2224885203",
+ "2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n",
+ "a914c579342c2c4c9220205e2cdc285617040c924a0a87",
{
- "isCompressed": false,
- "isPrivkey": true,
- "isTestnet": true
+ "isPrivkey": false,
+ "chain": "test"
}
- ],
+ ],
[
- "cTDVKtMGVYWTHCb1AFjmVbEbWjvKpKqKgMaR3QJxToMSQAhmCeTN",
- "a81ca4e8f90181ec4b61b6a7eb998af17b2cb04de8a03b504b9e34c4c61db7d9",
+ "5K494XZwps2bGyeL71pWid4noiSNA2cfCibrvRWqcHSptoFn7rc",
+ "a326b95ebae30164217d7a7f57d72ab2b54e3be64928a19da0210b9568d4015e",
{
- "isCompressed": true,
- "isPrivkey": true,
- "isTestnet": true
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "main"
}
- ],
+ ],
[
- "1C5bSj1iEGUgSTbziymG7Cn18ENQuT36vv",
- "7987ccaa53d02c8873487ef919677cd3db7a6912",
+ "L1RrrnXkcKut5DEMwtDthjwRcTTwED36thyL1DebVrKuwvohjMNi",
+ "7d998b45c219a1e38e99e7cbd312ef67f77a455a9b50c730c27f02c6f730dfb4",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": false
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "main"
}
- ],
+ ],
[
- "3AnNxabYGoTxYiTEZwFEnerUoeFXK2Zoks",
- "63bcc565f9e68ee0189dd5cc67f1b0e5f02f45cb",
+ "93DVKyFYwSN6wEo3E2fCrFPUp17FtrtNi2Lf7n4G3garFb16CRj",
+ "d6bca256b5abc5602ec2e1c121a08b0da2556587430bcf7e1898af2224885203",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": false
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "test"
}
- ],
+ ],
[
- "n3LnJXCqbPjghuVs8ph9CYsAe4Sh4j97wk",
- "ef66444b5b17f14e8fae6e7e19b045a78c54fd79",
+ "cTDVKtMGVYWTHCb1AFjmVbEbWjvKpKqKgMaR3QJxToMSQAhmCeTN",
+ "a81ca4e8f90181ec4b61b6a7eb998af17b2cb04de8a03b504b9e34c4c61db7d9",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": true
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "test"
}
- ],
+ ],
[
- "2NB72XtkjpnATMggui83aEtPawyyKvnbX2o",
- "c3e55fceceaa4391ed2a9677f4a4d34eacd021a0",
+ "1C5bSj1iEGUgSTbziymG7Cn18ENQuT36vv",
+ "76a9147987ccaa53d02c8873487ef919677cd3db7a691288ac",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": true
+ "isPrivkey": false,
+ "chain": "main"
}
- ],
+ ],
[
- "5KaBW9vNtWNhc3ZEDyNCiXLPdVPHCikRxSBWwV9NrpLLa4LsXi9",
- "e75d936d56377f432f404aabb406601f892fd49da90eb6ac558a733c93b47252",
+ "3AnNxabYGoTxYiTEZwFEnerUoeFXK2Zoks",
+ "a91463bcc565f9e68ee0189dd5cc67f1b0e5f02f45cb87",
{
- "isCompressed": false,
- "isPrivkey": true,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "main"
}
- ],
+ ],
[
- "L1axzbSyynNYA8mCAhzxkipKkfHtAXYF4YQnhSKcLV8YXA874fgT",
- "8248bd0375f2f75d7e274ae544fb920f51784480866b102384190b1addfbaa5c",
+ "n3LnJXCqbPjghuVs8ph9CYsAe4Sh4j97wk",
+ "76a914ef66444b5b17f14e8fae6e7e19b045a78c54fd7988ac",
{
- "isCompressed": true,
- "isPrivkey": true,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "test"
}
- ],
+ ],
[
- "927CnUkUbasYtDwYwVn2j8GdTuACNnKkjZ1rpZd2yBB1CLcnXpo",
- "44c4f6a096eac5238291a94cc24c01e3b19b8d8cef72874a079e00a242237a52",
+ "2NB72XtkjpnATMggui83aEtPawyyKvnbX2o",
+ "a914c3e55fceceaa4391ed2a9677f4a4d34eacd021a087",
{
- "isCompressed": false,
- "isPrivkey": true,
- "isTestnet": true
+ "isPrivkey": false,
+ "chain": "test"
}
- ],
+ ],
[
- "cUcfCMRjiQf85YMzzQEk9d1s5A4K7xL5SmBCLrezqXFuTVefyhY7",
- "d1de707020a9059d6d3abaf85e17967c6555151143db13dbb06db78df0f15c69",
+ "5KaBW9vNtWNhc3ZEDyNCiXLPdVPHCikRxSBWwV9NrpLLa4LsXi9",
+ "e75d936d56377f432f404aabb406601f892fd49da90eb6ac558a733c93b47252",
{
- "isCompressed": true,
- "isPrivkey": true,
- "isTestnet": true
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "main"
}
- ],
+ ],
[
- "1Gqk4Tv79P91Cc1STQtU3s1W6277M2CVWu",
- "adc1cc2081a27206fae25792f28bbc55b831549d",
+ "L1axzbSyynNYA8mCAhzxkipKkfHtAXYF4YQnhSKcLV8YXA874fgT",
+ "8248bd0375f2f75d7e274ae544fb920f51784480866b102384190b1addfbaa5c",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": false
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "main"
}
- ],
+ ],
[
- "33vt8ViH5jsr115AGkW6cEmEz9MpvJSwDk",
- "188f91a931947eddd7432d6e614387e32b244709",
+ "927CnUkUbasYtDwYwVn2j8GdTuACNnKkjZ1rpZd2yBB1CLcnXpo",
+ "44c4f6a096eac5238291a94cc24c01e3b19b8d8cef72874a079e00a242237a52",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": false
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "test"
}
- ],
+ ],
[
- "mhaMcBxNh5cqXm4aTQ6EcVbKtfL6LGyK2H",
- "1694f5bc1a7295b600f40018a618a6ea48eeb498",
+ "cUcfCMRjiQf85YMzzQEk9d1s5A4K7xL5SmBCLrezqXFuTVefyhY7",
+ "d1de707020a9059d6d3abaf85e17967c6555151143db13dbb06db78df0f15c69",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": true
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "test"
}
- ],
+ ],
[
- "2MxgPqX1iThW3oZVk9KoFcE5M4JpiETssVN",
- "3b9b3fd7a50d4f08d1a5b0f62f644fa7115ae2f3",
+ "1Gqk4Tv79P91Cc1STQtU3s1W6277M2CVWu",
+ "76a914adc1cc2081a27206fae25792f28bbc55b831549d88ac",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": true
+ "isPrivkey": false,
+ "chain": "main"
}
- ],
+ ],
[
- "5HtH6GdcwCJA4ggWEL1B3jzBBUB8HPiBi9SBc5h9i4Wk4PSeApR",
- "091035445ef105fa1bb125eccfb1882f3fe69592265956ade751fd095033d8d0",
+ "33vt8ViH5jsr115AGkW6cEmEz9MpvJSwDk",
+ "a914188f91a931947eddd7432d6e614387e32b24470987",
{
- "isCompressed": false,
- "isPrivkey": true,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "main"
}
- ],
+ ],
[
- "L2xSYmMeVo3Zek3ZTsv9xUrXVAmrWxJ8Ua4cw8pkfbQhcEFhkXT8",
- "ab2b4bcdfc91d34dee0ae2a8c6b6668dadaeb3a88b9859743156f462325187af",
+ "mhaMcBxNh5cqXm4aTQ6EcVbKtfL6LGyK2H",
+ "76a9141694f5bc1a7295b600f40018a618a6ea48eeb49888ac",
{
- "isCompressed": true,
- "isPrivkey": true,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "test"
}
- ],
+ ],
[
- "92xFEve1Z9N8Z641KQQS7ByCSb8kGjsDzw6fAmjHN1LZGKQXyMq",
- "b4204389cef18bbe2b353623cbf93e8678fbc92a475b664ae98ed594e6cf0856",
+ "2MxgPqX1iThW3oZVk9KoFcE5M4JpiETssVN",
+ "a9143b9b3fd7a50d4f08d1a5b0f62f644fa7115ae2f387",
{
- "isCompressed": false,
- "isPrivkey": true,
- "isTestnet": true
+ "isPrivkey": false,
+ "chain": "test"
}
- ],
+ ],
[
- "cVM65tdYu1YK37tNoAyGoJTR13VBYFva1vg9FLuPAsJijGvG6NEA",
- "e7b230133f1b5489843260236b06edca25f66adb1be455fbd38d4010d48faeef",
+ "5HtH6GdcwCJA4ggWEL1B3jzBBUB8HPiBi9SBc5h9i4Wk4PSeApR",
+ "091035445ef105fa1bb125eccfb1882f3fe69592265956ade751fd095033d8d0",
{
- "isCompressed": true,
- "isPrivkey": true,
- "isTestnet": true
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "main"
}
- ],
+ ],
[
- "1JwMWBVLtiqtscbaRHai4pqHokhFCbtoB4",
- "c4c1b72491ede1eedaca00618407ee0b772cad0d",
+ "L2xSYmMeVo3Zek3ZTsv9xUrXVAmrWxJ8Ua4cw8pkfbQhcEFhkXT8",
+ "ab2b4bcdfc91d34dee0ae2a8c6b6668dadaeb3a88b9859743156f462325187af",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": false
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "main"
}
- ],
+ ],
[
- "3QCzvfL4ZRvmJFiWWBVwxfdaNBT8EtxB5y",
- "f6fe69bcb548a829cce4c57bf6fff8af3a5981f9",
+ "92xFEve1Z9N8Z641KQQS7ByCSb8kGjsDzw6fAmjHN1LZGKQXyMq",
+ "b4204389cef18bbe2b353623cbf93e8678fbc92a475b664ae98ed594e6cf0856",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": false
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "test"
}
- ],
+ ],
[
- "mizXiucXRCsEriQCHUkCqef9ph9qtPbZZ6",
- "261f83568a098a8638844bd7aeca039d5f2352c0",
+ "92xFEve1Z9N8Z641KQQS7ByCSb8kGjsDzw6fAmjHN1LZGKQXyMq",
+ "b4204389cef18bbe2b353623cbf93e8678fbc92a475b664ae98ed594e6cf0856",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": true
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "regtest"
}
- ],
+ ],
[
- "2NEWDzHWwY5ZZp8CQWbB7ouNMLqCia6YRda",
- "e930e1834a4d234702773951d627cce82fbb5d2e",
+ "cVM65tdYu1YK37tNoAyGoJTR13VBYFva1vg9FLuPAsJijGvG6NEA",
+ "e7b230133f1b5489843260236b06edca25f66adb1be455fbd38d4010d48faeef",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": true
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "test"
}
- ],
+ ],
[
- "5KQmDryMNDcisTzRp3zEq9e4awRmJrEVU1j5vFRTKpRNYPqYrMg",
- "d1fab7ab7385ad26872237f1eb9789aa25cc986bacc695e07ac571d6cdac8bc0",
+ "1JwMWBVLtiqtscbaRHai4pqHokhFCbtoB4",
+ "76a914c4c1b72491ede1eedaca00618407ee0b772cad0d88ac",
{
- "isCompressed": false,
- "isPrivkey": true,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "main"
}
- ],
+ ],
[
- "L39Fy7AC2Hhj95gh3Yb2AU5YHh1mQSAHgpNixvm27poizcJyLtUi",
- "b0bbede33ef254e8376aceb1510253fc3550efd0fcf84dcd0c9998b288f166b3",
+ "3QCzvfL4ZRvmJFiWWBVwxfdaNBT8EtxB5y",
+ "a914f6fe69bcb548a829cce4c57bf6fff8af3a5981f987",
{
- "isCompressed": true,
- "isPrivkey": true,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "main"
}
- ],
+ ],
[
- "91cTVUcgydqyZLgaANpf1fvL55FH53QMm4BsnCADVNYuWuqdVys",
- "037f4192c630f399d9271e26c575269b1d15be553ea1a7217f0cb8513cef41cb",
+ "mizXiucXRCsEriQCHUkCqef9ph9qtPbZZ6",
+ "76a914261f83568a098a8638844bd7aeca039d5f2352c088ac",
{
- "isCompressed": false,
- "isPrivkey": true,
- "isTestnet": true
+ "isPrivkey": false,
+ "chain": "test"
}
- ],
+ ],
[
- "cQspfSzsgLeiJGB2u8vrAiWpCU4MxUT6JseWo2SjXy4Qbzn2fwDw",
- "6251e205e8ad508bab5596bee086ef16cd4b239e0cc0c5d7c4e6035441e7d5de",
+ "2NEWDzHWwY5ZZp8CQWbB7ouNMLqCia6YRda",
+ "a914e930e1834a4d234702773951d627cce82fbb5d2e87",
{
- "isCompressed": true,
- "isPrivkey": true,
- "isTestnet": true
+ "isPrivkey": false,
+ "chain": "test"
}
- ],
+ ],
[
- "19dcawoKcZdQz365WpXWMhX6QCUpR9SY4r",
- "5eadaf9bb7121f0f192561a5a62f5e5f54210292",
+ "5KQmDryMNDcisTzRp3zEq9e4awRmJrEVU1j5vFRTKpRNYPqYrMg",
+ "d1fab7ab7385ad26872237f1eb9789aa25cc986bacc695e07ac571d6cdac8bc0",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": false
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "main"
}
- ],
+ ],
[
- "37Sp6Rv3y4kVd1nQ1JV5pfqXccHNyZm1x3",
- "3f210e7277c899c3a155cc1c90f4106cbddeec6e",
+ "L39Fy7AC2Hhj95gh3Yb2AU5YHh1mQSAHgpNixvm27poizcJyLtUi",
+ "b0bbede33ef254e8376aceb1510253fc3550efd0fcf84dcd0c9998b288f166b3",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": false
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "main"
}
- ],
+ ],
[
- "myoqcgYiehufrsnnkqdqbp69dddVDMopJu",
- "c8a3c2a09a298592c3e180f02487cd91ba3400b5",
+ "91cTVUcgydqyZLgaANpf1fvL55FH53QMm4BsnCADVNYuWuqdVys",
+ "037f4192c630f399d9271e26c575269b1d15be553ea1a7217f0cb8513cef41cb",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": true
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "test"
}
- ],
+ ],
[
- "2N7FuwuUuoTBrDFdrAZ9KxBmtqMLxce9i1C",
- "99b31df7c9068d1481b596578ddbb4d3bd90baeb",
+ "cQspfSzsgLeiJGB2u8vrAiWpCU4MxUT6JseWo2SjXy4Qbzn2fwDw",
+ "6251e205e8ad508bab5596bee086ef16cd4b239e0cc0c5d7c4e6035441e7d5de",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": true
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "test"
}
- ],
+ ],
[
- "5KL6zEaMtPRXZKo1bbMq7JDjjo1bJuQcsgL33je3oY8uSJCR5b4",
- "c7666842503db6dc6ea061f092cfb9c388448629a6fe868d068c42a488b478ae",
+ "19dcawoKcZdQz365WpXWMhX6QCUpR9SY4r",
+ "76a9145eadaf9bb7121f0f192561a5a62f5e5f5421029288ac",
{
- "isCompressed": false,
- "isPrivkey": true,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "main"
}
- ],
+ ],
[
- "KwV9KAfwbwt51veZWNscRTeZs9CKpojyu1MsPnaKTF5kz69H1UN2",
- "07f0803fc5399e773555ab1e8939907e9badacc17ca129e67a2f5f2ff84351dd",
+ "37Sp6Rv3y4kVd1nQ1JV5pfqXccHNyZm1x3",
+ "a9143f210e7277c899c3a155cc1c90f4106cbddeec6e87",
{
- "isCompressed": true,
- "isPrivkey": true,
- "isTestnet": false
+ "isPrivkey": false,
+ "chain": "main"
}
- ],
+ ],
[
- "93N87D6uxSBzwXvpokpzg8FFmfQPmvX4xHoWQe3pLdYpbiwT5YV",
- "ea577acfb5d1d14d3b7b195c321566f12f87d2b77ea3a53f68df7ebf8604a801",
+ "myoqcgYiehufrsnnkqdqbp69dddVDMopJu",
+ "76a914c8a3c2a09a298592c3e180f02487cd91ba3400b588ac",
{
- "isCompressed": false,
- "isPrivkey": true,
- "isTestnet": true
+ "isPrivkey": false,
+ "chain": "test"
}
- ],
+ ],
[
- "cMxXusSihaX58wpJ3tNuuUcZEQGt6DKJ1wEpxys88FFaQCYjku9h",
- "0b3b34f0958d8a268193a9814da92c3e8b58b4a4378a542863e34ac289cd830c",
+ "2N7FuwuUuoTBrDFdrAZ9KxBmtqMLxce9i1C",
+ "a91499b31df7c9068d1481b596578ddbb4d3bd90baeb87",
{
- "isCompressed": true,
- "isPrivkey": true,
- "isTestnet": true
+ "isPrivkey": false,
+ "chain": "test"
}
- ],
+ ],
[
- "13p1ijLwsnrcuyqcTvJXkq2ASdXqcnEBLE",
- "1ed467017f043e91ed4c44b4e8dd674db211c4e6",
+ "5KL6zEaMtPRXZKo1bbMq7JDjjo1bJuQcsgL33je3oY8uSJCR5b4",
+ "c7666842503db6dc6ea061f092cfb9c388448629a6fe868d068c42a488b478ae",
{
- "addrType": "pubkey",
- "isPrivkey": false,
- "isTestnet": false
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "main"
}
- ],
+ ],
[
- "3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G",
- "5ece0cadddc415b1980f001785947120acdb36fc",
+ "KwV9KAfwbwt51veZWNscRTeZs9CKpojyu1MsPnaKTF5kz69H1UN2",
+ "07f0803fc5399e773555ab1e8939907e9badacc17ca129e67a2f5f2ff84351dd",
{
- "addrType": "script",
- "isPrivkey": false,
- "isTestnet": false
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "main"
+ }
+ ],
+ [
+ "93N87D6uxSBzwXvpokpzg8FFmfQPmvX4xHoWQe3pLdYpbiwT5YV",
+ "ea577acfb5d1d14d3b7b195c321566f12f87d2b77ea3a53f68df7ebf8604a801",
+ {
+ "isCompressed": false,
+ "isPrivkey": true,
+ "chain": "test"
+ }
+ ],
+ [
+ "cMxXusSihaX58wpJ3tNuuUcZEQGt6DKJ1wEpxys88FFaQCYjku9h",
+ "0b3b34f0958d8a268193a9814da92c3e8b58b4a4378a542863e34ac289cd830c",
+ {
+ "isCompressed": true,
+ "isPrivkey": true,
+ "chain": "test"
+ }
+ ],
+ [
+ "13p1ijLwsnrcuyqcTvJXkq2ASdXqcnEBLE",
+ "76a9141ed467017f043e91ed4c44b4e8dd674db211c4e688ac",
+ {
+ "isPrivkey": false,
+ "chain": "main"
+ }
+ ],
+ [
+ "3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G",
+ "a9145ece0cadddc415b1980f001785947120acdb36fc87",
+ {
+ "isPrivkey": false,
+ "chain": "main"
+ }
+ ],
+ [
+ "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4",
+ "0014751e76e8199196d454941c45d1b3a323f1433bd6",
+ {
+ "isPrivkey": false,
+ "chain": "main",
+ "tryCaseFlip": true
+ }
+ ],
+ [
+ "bcrt1qw508d6qejxtdg4y5r3zarvary0c5xw7kygt080",
+ "0014751e76e8199196d454941c45d1b3a323f1433bd6",
+ {
+ "isPrivkey": false,
+ "chain": "regtest",
+ "tryCaseFlip": true
+ }
+ ],
+ [
+ "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
+ "00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262",
+ {
+ "isPrivkey": false,
+ "chain": "test",
+ "tryCaseFlip": true
+ }
+ ],
+ [
+ "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx",
+ "5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6",
+ {
+ "isPrivkey": false,
+ "chain": "main",
+ "tryCaseFlip": true
+ }
+ ],
+ [
+ "bc1sw50qa3jx3s",
+ "6002751e",
+ {
+ "isPrivkey": false,
+ "chain": "main",
+ "tryCaseFlip": true
+ }
+ ],
+ [
+ "bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj",
+ "5210751e76e8199196d454941c45d1b3a323",
+ {
+ "isPrivkey": false,
+ "chain": "main",
+ "tryCaseFlip": true
+ }
+ ],
+ [
+ "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy",
+ "0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433",
+ {
+ "isPrivkey": false,
+ "chain": "test",
+ "tryCaseFlip": true
+ }
+ ],
+ [
+ "bcrt1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvseswlauz7",
+ "0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433",
+ {
+ "isPrivkey": false,
+ "chain": "regtest",
+ "tryCaseFlip": true
}
]
]
diff --git a/src/test/data/bitcoin-util-test.json b/src/test/data/bitcoin-util-test.json
deleted file mode 100644
index a80ab51901..0000000000
--- a/src/test/data/bitcoin-util-test.json
+++ /dev/null
@@ -1,356 +0,0 @@
-[
- { "exec": "./bitcoin-tx",
- "args": ["-create", "nversion=1"],
- "output_cmp": "blanktxv1.hex",
- "description": "Creates a blank v1 transaction"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-json","-create", "nversion=1"],
- "output_cmp": "blanktxv1.json",
- "description": "Creates a blank v1 transaction (output in json)"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-"],
- "input": "blanktxv2.hex",
- "output_cmp": "blanktxv2.hex",
- "description": "Creates a blank transaction when nothing is piped into bitcoin-tx"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-json","-create"],
- "output_cmp": "blanktxv2.json",
- "description": "Creates a blank transaction (output in json)"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-json","-"],
- "input": "blanktxv2.hex",
- "output_cmp": "blanktxv2.json",
- "description": "Creates a blank transaction when nothing is piped into bitcoin-tx (output in json)"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-", "delin=1"],
- "input": "tx394b54bb.hex",
- "output_cmp": "tt-delin1-out.hex",
- "description": "Deletes a single input from a transaction"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-json", "-", "delin=1"],
- "input": "tx394b54bb.hex",
- "output_cmp": "tt-delin1-out.json",
- "description": "Deletes a single input from a transaction (output in json)"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-", "delin=31"],
- "input": "tx394b54bb.hex",
- "return_code": 1,
- "description": "Attempts to delete an input with a bad index from a transaction. Expected to fail."
- },
- { "exec": "./bitcoin-tx",
- "args": ["-", "delout=1"],
- "input": "tx394b54bb.hex",
- "output_cmp": "tt-delout1-out.hex",
- "description": "Deletes a single output from a transaction"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-json", "-", "delout=1"],
- "input": "tx394b54bb.hex",
- "output_cmp": "tt-delout1-out.json",
- "description": "Deletes a single output from a transaction (output in json)"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-", "delout=2"],
- "input": "tx394b54bb.hex",
- "return_code": 1,
- "description": "Attempts to delete an output with a bad index from a transaction. Expected to fail."
- },
- { "exec": "./bitcoin-tx",
- "args": ["-", "locktime=317000"],
- "input": "tx394b54bb.hex",
- "output_cmp": "tt-locktime317000-out.hex",
- "description": "Adds an nlocktime to a transaction"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-json", "-", "locktime=317000"],
- "input": "tx394b54bb.hex",
- "output_cmp": "tt-locktime317000-out.json",
- "description": "Adds an nlocktime to a transaction (output in json)"
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["-create",
- "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0",
- "in=bf829c6bcf84579331337659d31f89dfd138f7f7785802d5501c92333145ca7c:18",
- "in=22a6f904655d53ae2ff70e701a0bbd90aa3975c0f40bfc6cc996a9049e31cdfc:1",
- "outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o",
- "outaddr=4:1P8yWvZW8jVihP1bzHeqfE4aoXNX8AVa46"],
- "output_cmp": "txcreate1.hex",
- "description": "Creates a new transaction with three inputs and two outputs"
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["-json",
- "-create",
- "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0",
- "in=bf829c6bcf84579331337659d31f89dfd138f7f7785802d5501c92333145ca7c:18",
- "in=22a6f904655d53ae2ff70e701a0bbd90aa3975c0f40bfc6cc996a9049e31cdfc:1",
- "outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o",
- "outaddr=4:1P8yWvZW8jVihP1bzHeqfE4aoXNX8AVa46"],
- "output_cmp": "txcreate1.json",
- "description": "Creates a new transaction with three inputs and two outputs (output in json)"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-create", "outscript=0:"],
- "output_cmp": "txcreate2.hex",
- "description": "Creates a new transaction with a single empty output script"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-json", "-create", "outscript=0:"],
- "output_cmp": "txcreate2.json",
- "description": "Creates a new transaction with a single empty output script (output in json)"
- },
- { "exec": "./bitcoin-tx",
- "args": ["02000000000100000000000000000000000000"],
- "output_cmp": "txcreate2.hex",
- "description": "Parses a transation with no inputs and a single output script"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-json", "02000000000100000000000000000000000000"],
- "output_cmp": "txcreate2.json",
- "description": "Parses a transation with no inputs and a single output script (output in json)"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-create", "outscript=0:OP_DROP", "nversion=1"],
- "output_cmp": "txcreatescript1.hex",
- "description": "Create a new transaction with a single output script (OP_DROP)"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-json", "-create", "outscript=0:OP_DROP", "nversion=1"],
- "output_cmp": "txcreatescript1.json",
- "description": "Create a new transaction with a single output script (OP_DROP) (output as json)"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-create", "outscript=0:OP_DROP:S", "nversion=1"],
- "output_cmp": "txcreatescript2.hex",
- "description": "Create a new transaction with a single output script (OP_DROP) in a P2SH"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-json", "-create", "outscript=0:OP_DROP:S", "nversion=1"],
- "output_cmp": "txcreatescript2.json",
- "description": "Create a new transaction with a single output script (OP_DROP) in a P2SH (output as json)"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-create", "outscript=0:OP_DROP:W", "nversion=1"],
- "output_cmp": "txcreatescript3.hex",
- "description": "Create a new transaction with a single output script (OP_DROP) in a P2WSH"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-json", "-create", "outscript=0:OP_DROP:W", "nversion=1"],
- "output_cmp": "txcreatescript3.json",
- "description": "Create a new transaction with a single output script (OP_DROP) in a P2WSH (output as json)"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-create", "outscript=0:OP_DROP:WS", "nversion=1"],
- "output_cmp": "txcreatescript4.hex",
- "description": "Create a new transaction with a single output script (OP_DROP) in a P2WSH, wrapped in a P2SH"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-json", "-create", "outscript=0:OP_DROP:WS", "nversion=1"],
- "output_cmp": "txcreatescript4.json",
- "description": "Create a new transaction with a single output script (OP_DROP) in a P2SH, wrapped in a P2SH (output as json)"
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["-create", "nversion=1",
- "in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0",
- "set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]",
- "set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\",\"vout\":0,\"scriptPubKey\":\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\"}]",
- "sign=ALL",
- "outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7"],
- "output_cmp": "txcreatesignv1.hex",
- "description": "Creates a new v1 transaction with a single input and a single output, and then signs the transaction"
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["-json",
- "-create", "nversion=1",
- "in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0",
- "set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]",
- "set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\",\"vout\":0,\"scriptPubKey\":\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\"}]",
- "sign=ALL",
- "outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7"],
- "output_cmp": "txcreatesignv1.json",
- "description": "Creates a new v1 transaction with a single input and a single output, and then signs the transaction (output in json)"
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["-create",
- "in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0",
- "set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]",
- "set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\",\"vout\":0,\"scriptPubKey\":\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\"}]",
- "sign=ALL",
- "outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7"],
- "output_cmp": "txcreatesignv2.hex",
- "description": "Creates a new transaction with a single input and a single output, and then signs the transaction"
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["-create", "outpubkey=0:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397", "nversion=1"],
- "output_cmp": "txcreateoutpubkey1.hex",
- "description": "Creates a new transaction with a single pay-to-pubkey output"
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["-json", "-create", "outpubkey=0:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397", "nversion=1"],
- "output_cmp": "txcreateoutpubkey1.json",
- "description": "Creates a new transaction with a single pay-to-pubkey output (output as json)"
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["-create", "outpubkey=0:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:W", "nversion=1"],
- "output_cmp": "txcreateoutpubkey2.hex",
- "description": "Creates a new transaction with a single pay-to-witness-pubkey output"
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["-json", "-create", "outpubkey=0:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:W", "nversion=1"],
- "output_cmp": "txcreateoutpubkey2.json",
- "description": "Creates a new transaction with a single pay-to-witness-pubkey output (output as json)"
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["-create", "outpubkey=0:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:WS", "nversion=1"],
- "output_cmp": "txcreateoutpubkey3.hex",
- "description": "Creates a new transaction with a single pay-to-witness-pubkey, wrapped in P2SH output"
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["-json", "-create", "outpubkey=0:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:WS", "nversion=1"],
- "output_cmp": "txcreateoutpubkey3.json",
- "description": "Creates a new transaction with a single pay-to-pub-key output, wrapped in P2SH (output as json)"
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["-create",
- "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0",
- "outdata=4:badhexdata"],
- "return_code": 1,
- "description": "Attempts to create a new transaction with one input and an output with malformed hex data. Expected to fail"
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["-create",
- "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0",
- "outdata=badhexdata"],
- "return_code": 1,
- "description": "Attempts to create a new transaction with one input and an output with no value and malformed hex data. Expected to fail"
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["-create",
- "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0",
- "outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o",
- "outdata=4:54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e"],
- "output_cmp": "txcreatedata1.hex",
- "description": "Creates a new transaction with one input, one address output and one data output"
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["-json",
- "-create", "nversion=1",
- "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0",
- "outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o",
- "outdata=4:54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e"],
- "output_cmp": "txcreatedata1.json",
- "description": "Creates a new v1 transaction with one input, one address output and one data output (output in json)"
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["-create",
- "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0",
- "outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o",
- "outdata=54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e"],
- "output_cmp": "txcreatedata2.hex",
- "description": "Creates a new transaction with one input, one address output and one data (zero value) output"
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["-json",
- "-create",
- "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0",
- "outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o",
- "outdata=54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e"],
- "output_cmp": "txcreatedata2.json",
- "description": "Creates a new transaction with one input, one address output and one data (zero value) output (output in json)"
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["-create",
- "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0:4294967293",
- "outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o"],
- "output_cmp": "txcreatedata_seq0.hex",
- "description": "Creates a new transaction with one input with sequence number and one address output"
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["-json",
- "-create",
- "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0:4294967293",
- "outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o"],
- "output_cmp": "txcreatedata_seq0.json",
- "description": "Creates a new transaction with one input with sequence number and one address output (output in json)"
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["01000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff0180a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac00000000",
- "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0:1"],
- "output_cmp": "txcreatedata_seq1.hex",
- "description": "Adds a new input with sequence number to a transaction"
- },
- { "exec": "./bitcoin-tx",
- "args":
- ["-json",
- "01000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff0180a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac00000000",
- "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0:1"],
- "output_cmp": "txcreatedata_seq1.json",
- "description": "Adds a new input with sequence number to a transaction (output in json)"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-create", "outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485", "nversion=1"],
- "output_cmp": "txcreatemultisig1.hex",
- "description": "Creates a new transaction with a single 2-of-3 multisig output"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-json", "-create", "outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485", "nversion=1"],
- "output_cmp": "txcreatemultisig1.json",
- "description": "Creates a new transaction with a single 2-of-3 multisig output (output in json)"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-create", "outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485:S", "nversion=1"],
- "output_cmp": "txcreatemultisig2.hex",
- "description": "Creates a new transaction with a single 2-of-3 multisig in a P2SH output"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-json", "-create", "outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485:S", "nversion=1"],
- "output_cmp": "txcreatemultisig2.json",
- "description": "Creates a new transaction with a single 2-of-3 multisig in a P2SH output (output in json)"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-create", "outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485:W", "nversion=1"],
- "output_cmp": "txcreatemultisig3.hex",
- "description": "Creates a new transaction with a single 2-of-3 multisig in a P2WSH output"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-json", "-create", "outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485:W", "nversion=1"],
- "output_cmp": "txcreatemultisig3.json",
- "description": "Creates a new transaction with a single 2-of-3 multisig in a P2WSH output (output in json)"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-create", "outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485:WS", "nversion=1"],
- "output_cmp": "txcreatemultisig4.hex",
- "description": "Creates a new transaction with a single 2-of-3 multisig in a P2WSH output, wrapped in P2SH"
- },
- { "exec": "./bitcoin-tx",
- "args": ["-json", "-create", "outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485:WS", "nversion=1"],
- "output_cmp": "txcreatemultisig4.json",
- "description": "Creates a new transaction with a single 2-of-3 multisig in a P2WSH output, wrapped in P2SH (output in json)"
- }
-]
diff --git a/src/test/data/blanktxv1.hex b/src/test/data/blanktxv1.hex
deleted file mode 100644
index 36b6f00fb6..0000000000
--- a/src/test/data/blanktxv1.hex
+++ /dev/null
@@ -1 +0,0 @@
-01000000000000000000
diff --git a/src/test/data/blanktxv1.json b/src/test/data/blanktxv1.json
deleted file mode 100644
index 51c25a5a98..0000000000
--- a/src/test/data/blanktxv1.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "txid": "d21633ba23f70118185227be58a63527675641ad37967e2aa461559f577aec43",
- "hash": "d21633ba23f70118185227be58a63527675641ad37967e2aa461559f577aec43",
- "version": 1,
- "locktime": 0,
- "vin": [
- ],
- "vout": [
- ],
- "hex": "01000000000000000000"
-}
diff --git a/src/test/data/blanktxv2.hex b/src/test/data/blanktxv2.hex
deleted file mode 100644
index 22d830eda1..0000000000
--- a/src/test/data/blanktxv2.hex
+++ /dev/null
@@ -1 +0,0 @@
-02000000000000000000
diff --git a/src/test/data/blanktxv2.json b/src/test/data/blanktxv2.json
deleted file mode 100644
index 266919f445..0000000000
--- a/src/test/data/blanktxv2.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "txid": "4ebd325a4b394cff8c57e8317ccf5a8d0e2bdf1b8526f8aad6c8e43d8240621a",
- "hash": "4ebd325a4b394cff8c57e8317ccf5a8d0e2bdf1b8526f8aad6c8e43d8240621a",
- "version": 2,
- "locktime": 0,
- "vin": [
- ],
- "vout": [
- ],
- "hex": "02000000000000000000"
-}
diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json
index 5c054ed3e8..698e898231 100644
--- a/src/test/data/script_tests.json
+++ b/src/test/data/script_tests.json
@@ -240,7 +240,7 @@
["0", "IF NOP10 ENDIF 1", "P2SH,STRICTENC,DISCOURAGE_UPGRADABLE_NOPS", "OK",
"Discouraged NOPs are allowed if not executed"],
-["0", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "OK", "opcodes above NOP10 invalid if executed"],
+["0", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "OK", "opcodes above MAX_OPCODE invalid if executed"],
["0", "IF 0xbb ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"],
["0", "IF 0xbc ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"],
["0", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"],
@@ -349,7 +349,7 @@
["2147483647", "0x04 0xFFFFFF7F EQUAL", "P2SH,STRICTENC", "OK"],
["2147483648", "0x05 0x0000008000 EQUAL", "P2SH,STRICTENC", "OK"],
["549755813887", "0x05 0xFFFFFFFF7F EQUAL", "P2SH,STRICTENC", "OK"],
-["549755813888", "0x06 0xFFFFFFFF7F EQUAL", "P2SH,STRICTENC", "OK"],
+["549755813888", "0x06 0x000000008000 EQUAL", "P2SH,STRICTENC", "OK"],
["9223372036854775807", "0x08 0xFFFFFFFFFFFFFF7F EQUAL", "P2SH,STRICTENC", "OK"],
["-1", "0x01 0x81 EQUAL", "P2SH,STRICTENC", "OK", "Numbers are little-endian with the MSB being a sign bit"],
["-127", "0x01 0xFF EQUAL", "P2SH,STRICTENC", "OK"],
@@ -878,7 +878,7 @@
"P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS", "Discouraged NOP10 in redeemScript"],
["0x50","1", "P2SH,STRICTENC", "BAD_OPCODE", "opcode 0x50 is reserved"],
-["1", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE", "opcodes above NOP10 invalid if executed"],
+["1", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE", "opcodes above MAX_OPCODE invalid if executed"],
["1", "IF 0xbb ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"],
["1", "IF 0xbc ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"],
["1", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"],
@@ -1001,7 +1001,7 @@
["1","RESERVED", "P2SH,STRICTENC", "BAD_OPCODE", "OP_RESERVED is reserved"],
["1","RESERVED1", "P2SH,STRICTENC", "BAD_OPCODE", "OP_RESERVED1 is reserved"],
["1","RESERVED2", "P2SH,STRICTENC", "BAD_OPCODE", "OP_RESERVED2 is reserved"],
-["1","0xba", "P2SH,STRICTENC", "BAD_OPCODE", "0xba == OP_NOP10 + 1"],
+["1","0xba", "P2SH,STRICTENC", "BAD_OPCODE", "0xba == MAX_OPCODE + 1"],
["2147483648", "1ADD 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do math on 5-byte integers"],
["2147483648", "NEGATE 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do math on 5-byte integers"],
@@ -2506,7 +2506,7 @@
],
["CHECKSEQUENCEVERIFY tests"],
-["", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "INVALID_STACK_OPERATION", "CSV automatically fails on a empty stack"],
+["", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "INVALID_STACK_OPERATION", "CSV automatically fails on an empty stack"],
["-1", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "NEGATIVE_LOCKTIME", "CSV automatically fails if stack top is negative"],
["0x0100", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY,MINIMALDATA", "UNKNOWN_ERROR", "CSV fails if stack top is not minimally encoded"],
["0", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "UNSATISFIED_LOCKTIME", "CSV fails if stack top bit 1 << 31 is set and the tx version < 2"],
diff --git a/src/test/data/tt-delin1-out.hex b/src/test/data/tt-delin1-out.hex
deleted file mode 100644
index 42ad840f43..0000000000
--- a/src/test/data/tt-delin1-out.hex
+++ /dev/null
@@ -1 +0,0 @@
-0100000014fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0260f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac41420f00000000001976a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac00000000
diff --git a/src/test/data/tt-delin1-out.json b/src/test/data/tt-delin1-out.json
deleted file mode 100644
index 712a2c27f8..0000000000
--- a/src/test/data/tt-delin1-out.json
+++ /dev/null
@@ -1,217 +0,0 @@
-{
- "txid": "81b2035be1da1abe745c6141174a73d151009ec17b3d5ebffa2e177408c50dfd",
- "hash": "81b2035be1da1abe745c6141174a73d151009ec17b3d5ebffa2e177408c50dfd",
- "version": 1,
- "locktime": 0,
- "vin": [
- {
- "txid": "27871a1a27d833e99cd392a502a647beaaeda6da535417501c76312d52235cfd",
- "vout": 332,
- "scriptSig": {
- "asm": "3046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc",
- "hex": "493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc"
- },
- "sequence": 4294967295
- },
- {
- "txid": "752f7f69b915637dc1c2f7aed1466ad676f6f3e24cf922809705f664e97ab3c1",
- "vout": 1,
- "scriptSig": {
- "asm": "3044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba[ALL] 027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34",
- "hex": "473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34"
- },
- "sequence": 4294967295
- },
- {
- "txid": "b0ac9cca2e69cd02410e31b1f4402a25758e71abd1ab06c265ef9077dc05d0ed",
- "vout": 209,
- "scriptSig": {
- "asm": "304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc",
- "hex": "48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc"
- },
- "sequence": 4294967295
- },
- {
- "txid": "a135eafb595eaf4c1ea59ccb111cdc0eae1b2c979b226a1e5aa8b76fe2d628df",
- "vout": 0,
- "scriptSig": {
- "asm": "3045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374[ALL] 03a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52",
- "hex": "483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52"
- },
- "sequence": 4294967295
- },
- {
- "txid": "a5d6bf53ba21140b8a4d554feb00fe8bb9a62430ff9e4624aa2f58a120232aae",
- "vout": 1,
- "scriptSig": {
- "asm": "3046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc",
- "hex": "493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc"
- },
- "sequence": 4294967295
- },
- {
- "txid": "1b299cf14f1a22e81ea56d71b7affbd7cf386807bf2b4d4b79a18a54125accb3",
- "vout": 0,
- "scriptSig": {
- "asm": "3045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967[ALL] 03a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52",
- "hex": "483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52"
- },
- "sequence": 4294967295
- },
- {
- "txid": "071df1cdcb3f0070f9d6af7b0274f02d0be2324a274727cfd288383167531485",
- "vout": 21,
- "scriptSig": {
- "asm": "3045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c",
- "hex": "483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c"
- },
- "sequence": 4294967295
- },
- {
- "txid": "b012e500eb7adf7a13ed332dd6ece849f94f7a62bb3eac5babab356d1fc19282",
- "vout": 9,
- "scriptSig": {
- "asm": "304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c",
- "hex": "48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c"
- },
- "sequence": 4294967295
- },
- {
- "txid": "58840fee9c833f2f2d40575842f30f4b8d2553094d06ad88b03d06869acf3d88",
- "vout": 30,
- "scriptSig": {
- "asm": "30440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c",
- "hex": "4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c"
- },
- "sequence": 4294967295
- },
- {
- "txid": "e69f9cd16946e570a665245354428a3f507ea69f4568b581e4af98edb3db9766",
- "vout": 114,
- "scriptSig": {
- "asm": "304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c",
- "hex": "47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c"
- },
- "sequence": 4294967295
- },
- {
- "txid": "595d1257f654ed2cbe5a65421e8aefd2b4d70b5b6c89a03f1d7e518221fc3f02",
- "vout": 103,
- "scriptSig": {
- "asm": "3046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc",
- "hex": "493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc"
- },
- "sequence": 4294967295
- },
- {
- "txid": "06fc818f9555a261248ecd7aad0993eafb5a82ceb2b5c87c3ddfb06671c7f816",
- "vout": 1,
- "scriptSig": {
- "asm": "3045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec7669018[ALL] 0234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd",
- "hex": "483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd"
- },
- "sequence": 4294967295
- },
- {
- "txid": "fb416c8155d6bb1d43f9395466ca90a638a7c2dd3ff617aadf3a7ac8f3967b19",
- "vout": 0,
- "scriptSig": {
- "asm": "304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a[ALL] 027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34",
- "hex": "49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34"
- },
- "sequence": 4294967295
- },
- {
- "txid": "3940b9683bd6104ad24c978e640ba4095993cafdb27d2ed91baa27ee61a2d920",
- "vout": 221,
- "scriptSig": {
- "asm": "3045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc",
- "hex": "483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc"
- },
- "sequence": 4294967295
- },
- {
- "txid": "711b5714d3b5136147c02194cd95bde94a4648c4263ca6f972d86cd1d579f150",
- "vout": 1,
- "scriptSig": {
- "asm": "3045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba9074[ALL] 0234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd",
- "hex": "483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd"
- },
- "sequence": 4294967295
- },
- {
- "txid": "6364b5c5efe018430789e7fb4e338209546cae5d9c5f5e300aac68155d861b55",
- "vout": 27,
- "scriptSig": {
- "asm": "304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c",
- "hex": "48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c"
- },
- "sequence": 4294967295
- },
- {
- "txid": "0bb57f6e38012c86d4c5a28c904f2675082859147921a707d48961015a3e5057",
- "vout": 1095,
- "scriptSig": {
- "asm": "304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c",
- "hex": "48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c"
- },
- "sequence": 4294967295
- },
- {
- "txid": "9b34274814a2540bb062107117f8f3e75ef85d953e9372d8261a3e9dfbc1163f",
- "vout": 37,
- "scriptSig": {
- "asm": "3045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c",
- "hex": "483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c"
- },
- "sequence": 4294967295
- },
- {
- "txid": "b86b5cc0d8a7374d94e277850b0a249cb26a7b42ddf014f28a49b8859da64241",
- "vout": 20,
- "scriptSig": {
- "asm": "304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c",
- "hex": "48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c"
- },
- "sequence": 4294967295
- },
- {
- "txid": "3d0a2353eeec44d3c10aed259038db321912122cd4150048f7bfa4c0ecfee236",
- "vout": 242,
- "scriptSig": {
- "asm": "3046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc",
- "hex": "493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc"
- },
- "sequence": 4294967295
- }
- ],
- "vout": [
- {
- "value": 1.3782,
- "n": 0,
- "scriptPubKey": {
- "asm": "OP_DUP OP_HASH160 8fd139bb39ced713f231c58a4d07bf6954d1c201 OP_EQUALVERIFY OP_CHECKSIG",
- "hex": "76a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac",
- "reqSigs": 1,
- "type": "pubkeyhash",
- "addresses": [
- "1E7SGgAZFCHDnVZLuRViX3gUmxpMfdvd2o"
- ]
- }
- },
- {
- "value": 0.01000001,
- "n": 1,
- "scriptPubKey": {
- "asm": "OP_DUP OP_HASH160 6c772e9cf96371bba3da8cb733da70a2fcf20078 OP_EQUALVERIFY OP_CHECKSIG",
- "hex": "76a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac",
- "reqSigs": 1,
- "type": "pubkeyhash",
- "addresses": [
- "1AtWkdmfmYkErU16d3KYykJUbEp9MAj9Sb"
- ]
- }
- }
- ],
- "hex": "0100000014fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0260f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac41420f00000000001976a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac00000000"
-}
diff --git a/src/test/data/tt-delout1-out.hex b/src/test/data/tt-delout1-out.hex
deleted file mode 100644
index cc60c3fac6..0000000000
--- a/src/test/data/tt-delout1-out.hex
+++ /dev/null
@@ -1 +0,0 @@
-0100000015fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffcb4ed1baba3a1eb2171e00ddec8e5b72b346dd8c07f9c2b0d122d0d06bc92ea7000000006c493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505ffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0160f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac00000000
diff --git a/src/test/data/tt-delout1-out.json b/src/test/data/tt-delout1-out.json
deleted file mode 100644
index afc4e95762..0000000000
--- a/src/test/data/tt-delout1-out.json
+++ /dev/null
@@ -1,213 +0,0 @@
-{
- "txid": "c46ccd75b5050e942b2e86a3648f843f525fe6fc000bf0534ba5973063354493",
- "hash": "c46ccd75b5050e942b2e86a3648f843f525fe6fc000bf0534ba5973063354493",
- "version": 1,
- "locktime": 0,
- "vin": [
- {
- "txid": "27871a1a27d833e99cd392a502a647beaaeda6da535417501c76312d52235cfd",
- "vout": 332,
- "scriptSig": {
- "asm": "3046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc",
- "hex": "493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc"
- },
- "sequence": 4294967295
- },
- {
- "txid": "a72ec96bd0d022d1b0c2f9078cdd46b3725b8eecdd001e17b21e3ababad14ecb",
- "vout": 0,
- "scriptSig": {
- "asm": "3046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba[ALL] 03e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505",
- "hex": "493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505"
- },
- "sequence": 4294967295
- },
- {
- "txid": "752f7f69b915637dc1c2f7aed1466ad676f6f3e24cf922809705f664e97ab3c1",
- "vout": 1,
- "scriptSig": {
- "asm": "3044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba[ALL] 027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34",
- "hex": "473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34"
- },
- "sequence": 4294967295
- },
- {
- "txid": "b0ac9cca2e69cd02410e31b1f4402a25758e71abd1ab06c265ef9077dc05d0ed",
- "vout": 209,
- "scriptSig": {
- "asm": "304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc",
- "hex": "48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc"
- },
- "sequence": 4294967295
- },
- {
- "txid": "a135eafb595eaf4c1ea59ccb111cdc0eae1b2c979b226a1e5aa8b76fe2d628df",
- "vout": 0,
- "scriptSig": {
- "asm": "3045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374[ALL] 03a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52",
- "hex": "483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52"
- },
- "sequence": 4294967295
- },
- {
- "txid": "a5d6bf53ba21140b8a4d554feb00fe8bb9a62430ff9e4624aa2f58a120232aae",
- "vout": 1,
- "scriptSig": {
- "asm": "3046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc",
- "hex": "493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc"
- },
- "sequence": 4294967295
- },
- {
- "txid": "1b299cf14f1a22e81ea56d71b7affbd7cf386807bf2b4d4b79a18a54125accb3",
- "vout": 0,
- "scriptSig": {
- "asm": "3045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967[ALL] 03a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52",
- "hex": "483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52"
- },
- "sequence": 4294967295
- },
- {
- "txid": "071df1cdcb3f0070f9d6af7b0274f02d0be2324a274727cfd288383167531485",
- "vout": 21,
- "scriptSig": {
- "asm": "3045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c",
- "hex": "483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c"
- },
- "sequence": 4294967295
- },
- {
- "txid": "b012e500eb7adf7a13ed332dd6ece849f94f7a62bb3eac5babab356d1fc19282",
- "vout": 9,
- "scriptSig": {
- "asm": "304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c",
- "hex": "48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c"
- },
- "sequence": 4294967295
- },
- {
- "txid": "58840fee9c833f2f2d40575842f30f4b8d2553094d06ad88b03d06869acf3d88",
- "vout": 30,
- "scriptSig": {
- "asm": "30440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c",
- "hex": "4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c"
- },
- "sequence": 4294967295
- },
- {
- "txid": "e69f9cd16946e570a665245354428a3f507ea69f4568b581e4af98edb3db9766",
- "vout": 114,
- "scriptSig": {
- "asm": "304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c",
- "hex": "47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c"
- },
- "sequence": 4294967295
- },
- {
- "txid": "595d1257f654ed2cbe5a65421e8aefd2b4d70b5b6c89a03f1d7e518221fc3f02",
- "vout": 103,
- "scriptSig": {
- "asm": "3046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc",
- "hex": "493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc"
- },
- "sequence": 4294967295
- },
- {
- "txid": "06fc818f9555a261248ecd7aad0993eafb5a82ceb2b5c87c3ddfb06671c7f816",
- "vout": 1,
- "scriptSig": {
- "asm": "3045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec7669018[ALL] 0234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd",
- "hex": "483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd"
- },
- "sequence": 4294967295
- },
- {
- "txid": "fb416c8155d6bb1d43f9395466ca90a638a7c2dd3ff617aadf3a7ac8f3967b19",
- "vout": 0,
- "scriptSig": {
- "asm": "304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a[ALL] 027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34",
- "hex": "49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34"
- },
- "sequence": 4294967295
- },
- {
- "txid": "3940b9683bd6104ad24c978e640ba4095993cafdb27d2ed91baa27ee61a2d920",
- "vout": 221,
- "scriptSig": {
- "asm": "3045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc",
- "hex": "483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc"
- },
- "sequence": 4294967295
- },
- {
- "txid": "711b5714d3b5136147c02194cd95bde94a4648c4263ca6f972d86cd1d579f150",
- "vout": 1,
- "scriptSig": {
- "asm": "3045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba9074[ALL] 0234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd",
- "hex": "483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd"
- },
- "sequence": 4294967295
- },
- {
- "txid": "6364b5c5efe018430789e7fb4e338209546cae5d9c5f5e300aac68155d861b55",
- "vout": 27,
- "scriptSig": {
- "asm": "304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c",
- "hex": "48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c"
- },
- "sequence": 4294967295
- },
- {
- "txid": "0bb57f6e38012c86d4c5a28c904f2675082859147921a707d48961015a3e5057",
- "vout": 1095,
- "scriptSig": {
- "asm": "304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c",
- "hex": "48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c"
- },
- "sequence": 4294967295
- },
- {
- "txid": "9b34274814a2540bb062107117f8f3e75ef85d953e9372d8261a3e9dfbc1163f",
- "vout": 37,
- "scriptSig": {
- "asm": "3045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c",
- "hex": "483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c"
- },
- "sequence": 4294967295
- },
- {
- "txid": "b86b5cc0d8a7374d94e277850b0a249cb26a7b42ddf014f28a49b8859da64241",
- "vout": 20,
- "scriptSig": {
- "asm": "304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c",
- "hex": "48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c"
- },
- "sequence": 4294967295
- },
- {
- "txid": "3d0a2353eeec44d3c10aed259038db321912122cd4150048f7bfa4c0ecfee236",
- "vout": 242,
- "scriptSig": {
- "asm": "3046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc",
- "hex": "493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc"
- },
- "sequence": 4294967295
- }
- ],
- "vout": [
- {
- "value": 1.3782,
- "n": 0,
- "scriptPubKey": {
- "asm": "OP_DUP OP_HASH160 8fd139bb39ced713f231c58a4d07bf6954d1c201 OP_EQUALVERIFY OP_CHECKSIG",
- "hex": "76a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac",
- "reqSigs": 1,
- "type": "pubkeyhash",
- "addresses": [
- "1E7SGgAZFCHDnVZLuRViX3gUmxpMfdvd2o"
- ]
- }
- }
- ],
- "hex": "0100000015fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffcb4ed1baba3a1eb2171e00ddec8e5b72b346dd8c07f9c2b0d122d0d06bc92ea7000000006c493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505ffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0160f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac00000000"
-}
diff --git a/src/test/data/tt-locktime317000-out.hex b/src/test/data/tt-locktime317000-out.hex
deleted file mode 100644
index 287f420a40..0000000000
--- a/src/test/data/tt-locktime317000-out.hex
+++ /dev/null
@@ -1 +0,0 @@
-0100000015fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffcb4ed1baba3a1eb2171e00ddec8e5b72b346dd8c07f9c2b0d122d0d06bc92ea7000000006c493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505ffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0260f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac41420f00000000001976a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac48d60400
diff --git a/src/test/data/tt-locktime317000-out.json b/src/test/data/tt-locktime317000-out.json
deleted file mode 100644
index 2b9075f8ac..0000000000
--- a/src/test/data/tt-locktime317000-out.json
+++ /dev/null
@@ -1,226 +0,0 @@
-{
- "txid": "aded538f642c17e15f4d3306b8be7e1a4d1ae0c4616d641ab51ea09ba65e5cb5",
- "hash": "aded538f642c17e15f4d3306b8be7e1a4d1ae0c4616d641ab51ea09ba65e5cb5",
- "version": 1,
- "locktime": 317000,
- "vin": [
- {
- "txid": "27871a1a27d833e99cd392a502a647beaaeda6da535417501c76312d52235cfd",
- "vout": 332,
- "scriptSig": {
- "asm": "3046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc",
- "hex": "493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc"
- },
- "sequence": 4294967295
- },
- {
- "txid": "a72ec96bd0d022d1b0c2f9078cdd46b3725b8eecdd001e17b21e3ababad14ecb",
- "vout": 0,
- "scriptSig": {
- "asm": "3046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba[ALL] 03e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505",
- "hex": "493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505"
- },
- "sequence": 4294967295
- },
- {
- "txid": "752f7f69b915637dc1c2f7aed1466ad676f6f3e24cf922809705f664e97ab3c1",
- "vout": 1,
- "scriptSig": {
- "asm": "3044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba[ALL] 027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34",
- "hex": "473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34"
- },
- "sequence": 4294967295
- },
- {
- "txid": "b0ac9cca2e69cd02410e31b1f4402a25758e71abd1ab06c265ef9077dc05d0ed",
- "vout": 209,
- "scriptSig": {
- "asm": "304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc",
- "hex": "48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc"
- },
- "sequence": 4294967295
- },
- {
- "txid": "a135eafb595eaf4c1ea59ccb111cdc0eae1b2c979b226a1e5aa8b76fe2d628df",
- "vout": 0,
- "scriptSig": {
- "asm": "3045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374[ALL] 03a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52",
- "hex": "483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52"
- },
- "sequence": 4294967295
- },
- {
- "txid": "a5d6bf53ba21140b8a4d554feb00fe8bb9a62430ff9e4624aa2f58a120232aae",
- "vout": 1,
- "scriptSig": {
- "asm": "3046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc",
- "hex": "493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc"
- },
- "sequence": 4294967295
- },
- {
- "txid": "1b299cf14f1a22e81ea56d71b7affbd7cf386807bf2b4d4b79a18a54125accb3",
- "vout": 0,
- "scriptSig": {
- "asm": "3045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967[ALL] 03a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52",
- "hex": "483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52"
- },
- "sequence": 4294967295
- },
- {
- "txid": "071df1cdcb3f0070f9d6af7b0274f02d0be2324a274727cfd288383167531485",
- "vout": 21,
- "scriptSig": {
- "asm": "3045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c",
- "hex": "483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c"
- },
- "sequence": 4294967295
- },
- {
- "txid": "b012e500eb7adf7a13ed332dd6ece849f94f7a62bb3eac5babab356d1fc19282",
- "vout": 9,
- "scriptSig": {
- "asm": "304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c",
- "hex": "48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c"
- },
- "sequence": 4294967295
- },
- {
- "txid": "58840fee9c833f2f2d40575842f30f4b8d2553094d06ad88b03d06869acf3d88",
- "vout": 30,
- "scriptSig": {
- "asm": "30440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c",
- "hex": "4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c"
- },
- "sequence": 4294967295
- },
- {
- "txid": "e69f9cd16946e570a665245354428a3f507ea69f4568b581e4af98edb3db9766",
- "vout": 114,
- "scriptSig": {
- "asm": "304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c",
- "hex": "47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c"
- },
- "sequence": 4294967295
- },
- {
- "txid": "595d1257f654ed2cbe5a65421e8aefd2b4d70b5b6c89a03f1d7e518221fc3f02",
- "vout": 103,
- "scriptSig": {
- "asm": "3046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc",
- "hex": "493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc"
- },
- "sequence": 4294967295
- },
- {
- "txid": "06fc818f9555a261248ecd7aad0993eafb5a82ceb2b5c87c3ddfb06671c7f816",
- "vout": 1,
- "scriptSig": {
- "asm": "3045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec7669018[ALL] 0234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd",
- "hex": "483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd"
- },
- "sequence": 4294967295
- },
- {
- "txid": "fb416c8155d6bb1d43f9395466ca90a638a7c2dd3ff617aadf3a7ac8f3967b19",
- "vout": 0,
- "scriptSig": {
- "asm": "304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a[ALL] 027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34",
- "hex": "49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34"
- },
- "sequence": 4294967295
- },
- {
- "txid": "3940b9683bd6104ad24c978e640ba4095993cafdb27d2ed91baa27ee61a2d920",
- "vout": 221,
- "scriptSig": {
- "asm": "3045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc",
- "hex": "483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc"
- },
- "sequence": 4294967295
- },
- {
- "txid": "711b5714d3b5136147c02194cd95bde94a4648c4263ca6f972d86cd1d579f150",
- "vout": 1,
- "scriptSig": {
- "asm": "3045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba9074[ALL] 0234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd",
- "hex": "483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cd"
- },
- "sequence": 4294967295
- },
- {
- "txid": "6364b5c5efe018430789e7fb4e338209546cae5d9c5f5e300aac68155d861b55",
- "vout": 27,
- "scriptSig": {
- "asm": "304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c",
- "hex": "48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c"
- },
- "sequence": 4294967295
- },
- {
- "txid": "0bb57f6e38012c86d4c5a28c904f2675082859147921a707d48961015a3e5057",
- "vout": 1095,
- "scriptSig": {
- "asm": "304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c",
- "hex": "48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c"
- },
- "sequence": 4294967295
- },
- {
- "txid": "9b34274814a2540bb062107117f8f3e75ef85d953e9372d8261a3e9dfbc1163f",
- "vout": 37,
- "scriptSig": {
- "asm": "3045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c",
- "hex": "483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c"
- },
- "sequence": 4294967295
- },
- {
- "txid": "b86b5cc0d8a7374d94e277850b0a249cb26a7b42ddf014f28a49b8859da64241",
- "vout": 20,
- "scriptSig": {
- "asm": "304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321[ALL] 03f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c",
- "hex": "48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64c"
- },
- "sequence": 4294967295
- },
- {
- "txid": "3d0a2353eeec44d3c10aed259038db321912122cd4150048f7bfa4c0ecfee236",
- "vout": 242,
- "scriptSig": {
- "asm": "3046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68[ALL] 03091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc",
- "hex": "493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adc"
- },
- "sequence": 4294967295
- }
- ],
- "vout": [
- {
- "value": 1.3782,
- "n": 0,
- "scriptPubKey": {
- "asm": "OP_DUP OP_HASH160 8fd139bb39ced713f231c58a4d07bf6954d1c201 OP_EQUALVERIFY OP_CHECKSIG",
- "hex": "76a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac",
- "reqSigs": 1,
- "type": "pubkeyhash",
- "addresses": [
- "1E7SGgAZFCHDnVZLuRViX3gUmxpMfdvd2o"
- ]
- }
- },
- {
- "value": 0.01000001,
- "n": 1,
- "scriptPubKey": {
- "asm": "OP_DUP OP_HASH160 6c772e9cf96371bba3da8cb733da70a2fcf20078 OP_EQUALVERIFY OP_CHECKSIG",
- "hex": "76a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac",
- "reqSigs": 1,
- "type": "pubkeyhash",
- "addresses": [
- "1AtWkdmfmYkErU16d3KYykJUbEp9MAj9Sb"
- ]
- }
- }
- ],
- "hex": "0100000015fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffcb4ed1baba3a1eb2171e00ddec8e5b72b346dd8c07f9c2b0d122d0d06bc92ea7000000006c493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505ffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0260f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac41420f00000000001976a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac48d60400"
-}
diff --git a/src/test/data/tx394b54bb.hex b/src/test/data/tx394b54bb.hex
deleted file mode 100644
index 33f26cb4d6..0000000000
--- a/src/test/data/tx394b54bb.hex
+++ /dev/null
@@ -1 +0,0 @@
-0100000015fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffcb4ed1baba3a1eb2171e00ddec8e5b72b346dd8c07f9c2b0d122d0d06bc92ea7000000006c493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505ffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0260f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac41420f00000000001976a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac00000000
diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json
index f7d9e1847f..09442b7f9f 100644
--- a/src/test/data/tx_invalid.json
+++ b/src/test/data/tx_invalid.json
@@ -1,7 +1,7 @@
[
["The following are deserialized transactions which are invalid."],
["They are in the form"],
-["[[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"],
+["[[[prevout hash, prevout index, prevout scriptPubKey, amount?], [input 2], ...],"],
["serializedTransaction, verifyFlags]"],
["Objects that are only a single string (like this one) are ignored"],
@@ -205,7 +205,7 @@
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feff40000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
-["By-time locks, with argument just beyond txin.nSequence (but within numerical boundries)"],
+["By-time locks, with argument just beyond txin.nSequence (but within numerical boundaries)"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194305 CHECKSEQUENCEVERIFY 1"]],
"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 CHECKSEQUENCEVERIFY 1"]],
diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json
index a3f47fcee2..ad74b7cf1b 100644
--- a/src/test/data/tx_valid.json
+++ b/src/test/data/tx_valid.json
@@ -1,7 +1,7 @@
[
["The following are deserialized transactions which are valid."],
["They are in the form"],
-["[[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"],
+["[[[prevout hash, prevout index, prevout scriptPubKey, amount?], [input 2], ...],"],
["serializedTransaction, verifyFlags]"],
["Objects that are only a single string (like this one) are ignored"],
@@ -45,7 +45,7 @@
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"],
["The following is f7fdd091fa6d8f5e7a8c2458f5c38faffff2d3f1406b6e4fe2c99dcc0d2d1cbb"],
-["It caught a bug in the workaround for 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63 in an overly simple implementation"],
+["It caught a bug in the workaround for 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63 in an overly simple implementation. In a signature, it contains an ASN1 integer which isn't strict-DER conformant due to being negative, which doesn't make sense in a signature. Before BIP66 activated, it was a valid signature. After it activated, it's not valid any more."],
[[["b464e85df2a238416f8bdae11d120add610380ea07f4ef19c5f9dfd472f96c3d", 0, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"],
["b7978cc96e59a8b13e0865d3f95657561a7f725be952438637475920bac9eb21", 1, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"]],
"01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000", "P2SH"],
@@ -174,7 +174,7 @@
[[["5a6b0021a6042a686b6b94abc36b387bef9109847774e8b1e51eb8cc55c53921", 1, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
"01000000012139c555ccb81ee5b1e87477840991ef7b386bc3ab946b6b682a04a621006b5a01000000fdb40148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f2204148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390175ac4830450220646b72c35beeec51f4d5bc1cbae01863825750d7f490864af354e6ea4f625e9c022100f04b98432df3a9641719dbced53393022e7249fb59db993af1118539830aab870148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a580039017521038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"],
-["Finally CHECKMULTISIG removes all signatures prior to hashing the script containing those signatures. In conjunction with the SIGHASH_SINGLE bug this lets us test whether or not FindAndDelete() is actually present in scriptPubKey/redeemScript evaluation by including a signature of the digest 0x01 We can compute in advance for our pubkey, embed it it in the scriptPubKey, and then also using a normal SIGHASH_ALL signature. If FindAndDelete() wasn't run, the 'bugged' signature would still be in the hashed script, and the normal signature would fail."],
+["Finally CHECKMULTISIG removes all signatures prior to hashing the script containing those signatures. In conjunction with the SIGHASH_SINGLE bug this lets us test whether or not FindAndDelete() is actually present in scriptPubKey/redeemScript evaluation by including a signature of the digest 0x01 We can compute in advance for our pubkey, embed it in the scriptPubKey, and then also using a normal SIGHASH_ALL signature. If FindAndDelete() wasn't run, the 'bugged' signature would still be in the hashed script, and the normal signature would fail."],
["Here's an example on mainnet within a P2SH redeemScript. Remarkably it's a standard transaction in <0.9"],
[[["b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9", 0, "DUP HASH160 0x14 0xf6f365c40f0739b61de827a44751e5e99032ed8f EQUALVERIFY CHECKSIG"],
diff --git a/src/test/data/txcreate1.hex b/src/test/data/txcreate1.hex
deleted file mode 100644
index 9ec6ee3531..0000000000
--- a/src/test/data/txcreate1.hex
+++ /dev/null
@@ -1 +0,0 @@
-02000000031f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff7cca453133921c50d5025878f7f738d1df891fd359763331935784cf6b9c82bf1200000000fffffffffccd319e04a996c96cfc0bf4c07539aa90bd0b1a700ef72fae535d6504f9a6220100000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0084d717000000001976a914f2d4db28cad6502226ee484ae24505c2885cb12d88ac00000000
diff --git a/src/test/data/txcreate1.json b/src/test/data/txcreate1.json
deleted file mode 100644
index f83e036f33..0000000000
--- a/src/test/data/txcreate1.json
+++ /dev/null
@@ -1,64 +0,0 @@
-{
- "txid": "fe7d174f42dce0cffa7a527e9bc8368956057619ec817648f6138b98f2533e8f",
- "hash": "fe7d174f42dce0cffa7a527e9bc8368956057619ec817648f6138b98f2533e8f",
- "version": 2,
- "locktime": 0,
- "vin": [
- {
- "txid": "5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f",
- "vout": 0,
- "scriptSig": {
- "asm": "",
- "hex": ""
- },
- "sequence": 4294967295
- },
- {
- "txid": "bf829c6bcf84579331337659d31f89dfd138f7f7785802d5501c92333145ca7c",
- "vout": 18,
- "scriptSig": {
- "asm": "",
- "hex": ""
- },
- "sequence": 4294967295
- },
- {
- "txid": "22a6f904655d53ae2ff70e701a0bbd90aa3975c0f40bfc6cc996a9049e31cdfc",
- "vout": 1,
- "scriptSig": {
- "asm": "",
- "hex": ""
- },
- "sequence": 4294967295
- }
- ],
- "vout": [
- {
- "value": 0.18,
- "n": 0,
- "scriptPubKey": {
- "asm": "OP_DUP OP_HASH160 1fc11f39be1729bf973a7ab6a615ca4729d64574 OP_EQUALVERIFY OP_CHECKSIG",
- "hex": "76a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac",
- "reqSigs": 1,
- "type": "pubkeyhash",
- "addresses": [
- "13tuJJDR2RgArmgfv6JScSdreahzgc4T6o"
- ]
- }
- },
- {
- "value": 4.00,
- "n": 1,
- "scriptPubKey": {
- "asm": "OP_DUP OP_HASH160 f2d4db28cad6502226ee484ae24505c2885cb12d OP_EQUALVERIFY OP_CHECKSIG",
- "hex": "76a914f2d4db28cad6502226ee484ae24505c2885cb12d88ac",
- "reqSigs": 1,
- "type": "pubkeyhash",
- "addresses": [
- "1P8yWvZW8jVihP1bzHeqfE4aoXNX8AVa46"
- ]
- }
- }
- ],
- "hex": "02000000031f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff7cca453133921c50d5025878f7f738d1df891fd359763331935784cf6b9c82bf1200000000fffffffffccd319e04a996c96cfc0bf4c07539aa90bd0b1a700ef72fae535d6504f9a6220100000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0084d717000000001976a914f2d4db28cad6502226ee484ae24505c2885cb12d88ac00000000"
-}
diff --git a/src/test/data/txcreate2.hex b/src/test/data/txcreate2.hex
deleted file mode 100644
index 38bb7b1046..0000000000
--- a/src/test/data/txcreate2.hex
+++ /dev/null
@@ -1 +0,0 @@
-02000000000100000000000000000000000000
diff --git a/src/test/data/txcreate2.json b/src/test/data/txcreate2.json
deleted file mode 100644
index fb5e177db7..0000000000
--- a/src/test/data/txcreate2.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "txid": "0481afb29931341d0d7861d8a2f6f26456fa042abf54a23e96440ed7946e0715",
- "hash": "0481afb29931341d0d7861d8a2f6f26456fa042abf54a23e96440ed7946e0715",
- "version": 2,
- "locktime": 0,
- "vin": [
- ],
- "vout": [
- {
- "value": 0.00,
- "n": 0,
- "scriptPubKey": {
- "asm": "",
- "hex": "",
- "type": "nonstandard"
- }
- }
- ],
- "hex": "02000000000100000000000000000000000000"
-}
diff --git a/src/test/data/txcreatedata1.hex b/src/test/data/txcreatedata1.hex
deleted file mode 100644
index cefd1a05a6..0000000000
--- a/src/test/data/txcreatedata1.hex
+++ /dev/null
@@ -1 +0,0 @@
-02000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0084d71700000000526a4c4f54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e00000000
diff --git a/src/test/data/txcreatedata1.json b/src/test/data/txcreatedata1.json
deleted file mode 100644
index 760518d30a..0000000000
--- a/src/test/data/txcreatedata1.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- "txid": "07894b4d12fe7853dd911402db1620920d261b9627c447f931417d330c25f06e",
- "hash": "07894b4d12fe7853dd911402db1620920d261b9627c447f931417d330c25f06e",
- "version": 1,
- "locktime": 0,
- "vin": [
- {
- "txid": "5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f",
- "vout": 0,
- "scriptSig": {
- "asm": "",
- "hex": ""
- },
- "sequence": 4294967295
- }
- ],
- "vout": [
- {
- "value": 0.18,
- "n": 0,
- "scriptPubKey": {
- "asm": "OP_DUP OP_HASH160 1fc11f39be1729bf973a7ab6a615ca4729d64574 OP_EQUALVERIFY OP_CHECKSIG",
- "hex": "76a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac",
- "reqSigs": 1,
- "type": "pubkeyhash",
- "addresses": [
- "13tuJJDR2RgArmgfv6JScSdreahzgc4T6o"
- ]
- }
- },
- {
- "value": 4.00,
- "n": 1,
- "scriptPubKey": {
- "asm": "OP_RETURN 54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e",
- "hex": "6a4c4f54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e",
- "type": "nulldata"
- }
- }
- ],
- "hex": "01000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0084d71700000000526a4c4f54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e00000000"
-}
diff --git a/src/test/data/txcreatedata2.hex b/src/test/data/txcreatedata2.hex
deleted file mode 100644
index d69cf58ba1..0000000000
--- a/src/test/data/txcreatedata2.hex
+++ /dev/null
@@ -1 +0,0 @@
-02000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0000000000000000526a4c4f54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e00000000
diff --git a/src/test/data/txcreatedata2.json b/src/test/data/txcreatedata2.json
deleted file mode 100644
index 3c6da40f90..0000000000
--- a/src/test/data/txcreatedata2.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- "txid": "c14b007fa3a6c1e7765919c1d14c1cfc2b8642c3a5d3be4b1fa8c4ccfec98bb0",
- "hash": "c14b007fa3a6c1e7765919c1d14c1cfc2b8642c3a5d3be4b1fa8c4ccfec98bb0",
- "version": 2,
- "locktime": 0,
- "vin": [
- {
- "txid": "5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f",
- "vout": 0,
- "scriptSig": {
- "asm": "",
- "hex": ""
- },
- "sequence": 4294967295
- }
- ],
- "vout": [
- {
- "value": 0.18,
- "n": 0,
- "scriptPubKey": {
- "asm": "OP_DUP OP_HASH160 1fc11f39be1729bf973a7ab6a615ca4729d64574 OP_EQUALVERIFY OP_CHECKSIG",
- "hex": "76a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac",
- "reqSigs": 1,
- "type": "pubkeyhash",
- "addresses": [
- "13tuJJDR2RgArmgfv6JScSdreahzgc4T6o"
- ]
- }
- },
- {
- "value": 0.00,
- "n": 1,
- "scriptPubKey": {
- "asm": "OP_RETURN 54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e",
- "hex": "6a4c4f54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e",
- "type": "nulldata"
- }
- }
- ],
- "hex": "02000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0000000000000000526a4c4f54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e00000000"
-}
diff --git a/src/test/data/txcreatedata_seq0.hex b/src/test/data/txcreatedata_seq0.hex
deleted file mode 100644
index 54b89d2381..0000000000
--- a/src/test/data/txcreatedata_seq0.hex
+++ /dev/null
@@ -1 +0,0 @@
-02000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff0180a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac00000000
diff --git a/src/test/data/txcreatedata_seq0.json b/src/test/data/txcreatedata_seq0.json
deleted file mode 100644
index d272a4c447..0000000000
--- a/src/test/data/txcreatedata_seq0.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "txid": "8df6ed527472542dd5e137c242a7c5a9f337ac34f7b257ae4af886aeaebb51b0",
- "hash": "8df6ed527472542dd5e137c242a7c5a9f337ac34f7b257ae4af886aeaebb51b0",
- "version": 2,
- "locktime": 0,
- "vin": [
- {
- "txid": "5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f",
- "vout": 0,
- "scriptSig": {
- "asm": "",
- "hex": ""
- },
- "sequence": 4294967293
- }
- ],
- "vout": [
- {
- "value": 0.18,
- "n": 0,
- "scriptPubKey": {
- "asm": "OP_DUP OP_HASH160 1fc11f39be1729bf973a7ab6a615ca4729d64574 OP_EQUALVERIFY OP_CHECKSIG",
- "hex": "76a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac",
- "reqSigs": 1,
- "type": "pubkeyhash",
- "addresses": [
- "13tuJJDR2RgArmgfv6JScSdreahzgc4T6o"
- ]
- }
- }
- ],
- "hex": "02000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff0180a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac00000000"
-}
diff --git a/src/test/data/txcreatedata_seq1.hex b/src/test/data/txcreatedata_seq1.hex
deleted file mode 100644
index 4cedcd975c..0000000000
--- a/src/test/data/txcreatedata_seq1.hex
+++ /dev/null
@@ -1 +0,0 @@
-01000000021f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff1f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000010000000180a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac00000000
diff --git a/src/test/data/txcreatedata_seq1.json b/src/test/data/txcreatedata_seq1.json
deleted file mode 100644
index d323255418..0000000000
--- a/src/test/data/txcreatedata_seq1.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- "txid": "c4dea671b0d7b48f8ab10bc46650e8329d3c5766931f548f513847a19f5ba75b",
- "hash": "c4dea671b0d7b48f8ab10bc46650e8329d3c5766931f548f513847a19f5ba75b",
- "version": 1,
- "locktime": 0,
- "vin": [
- {
- "txid": "5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f",
- "vout": 0,
- "scriptSig": {
- "asm": "",
- "hex": ""
- },
- "sequence": 4294967293
- },
- {
- "txid": "5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f",
- "vout": 0,
- "scriptSig": {
- "asm": "",
- "hex": ""
- },
- "sequence": 1
- }
- ],
- "vout": [
- {
- "value": 0.18,
- "n": 0,
- "scriptPubKey": {
- "asm": "OP_DUP OP_HASH160 1fc11f39be1729bf973a7ab6a615ca4729d64574 OP_EQUALVERIFY OP_CHECKSIG",
- "hex": "76a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac",
- "reqSigs": 1,
- "type": "pubkeyhash",
- "addresses": [
- "13tuJJDR2RgArmgfv6JScSdreahzgc4T6o"
- ]
- }
- }
- ],
- "hex": "01000000021f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff1f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000010000000180a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac00000000"
-}
diff --git a/src/test/data/txcreatemultisig1.hex b/src/test/data/txcreatemultisig1.hex
deleted file mode 100644
index 9c00004d38..0000000000
--- a/src/test/data/txcreatemultisig1.hex
+++ /dev/null
@@ -1 +0,0 @@
-01000000000100e1f5050000000069522102a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff39721021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d2102df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb48553ae00000000
diff --git a/src/test/data/txcreatemultisig1.json b/src/test/data/txcreatemultisig1.json
deleted file mode 100644
index f6ce43c202..0000000000
--- a/src/test/data/txcreatemultisig1.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "txid": "0d1d4edfc217d9db3ab6a9298f26a52eae3c52f55a6cb8ccbc14f7c727572894",
- "hash": "0d1d4edfc217d9db3ab6a9298f26a52eae3c52f55a6cb8ccbc14f7c727572894",
- "version": 1,
- "locktime": 0,
- "vin": [
- ],
- "vout": [
- {
- "value": 1.00,
- "n": 0,
- "scriptPubKey": {
- "asm": "2 02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397 021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d 02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485 3 OP_CHECKMULTISIG",
- "hex": "522102a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff39721021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d2102df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb48553ae",
- "reqSigs": 2,
- "type": "multisig",
- "addresses": [
- "1FoG2386FG2tAJS9acMuiDsKy67aGg9MKz",
- "1FXtz9KU8JNmQDyHdiEm5HDiALuP3zdHvV",
- "14LuavcBbXZYJ6Tsz3cAUQj9SuQoL2xCQX"
- ]
- }
- }
- ],
- "hex": "01000000000100e1f5050000000069522102a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff39721021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d2102df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb48553ae00000000"
-}
diff --git a/src/test/data/txcreatemultisig2.hex b/src/test/data/txcreatemultisig2.hex
deleted file mode 100644
index 07835c54d3..0000000000
--- a/src/test/data/txcreatemultisig2.hex
+++ /dev/null
@@ -1 +0,0 @@
-01000000000100e1f5050000000017a9141c6fbaf46d64221e80cbae182c33ddf81b9294ac8700000000
diff --git a/src/test/data/txcreatemultisig2.json b/src/test/data/txcreatemultisig2.json
deleted file mode 100644
index e09d22060f..0000000000
--- a/src/test/data/txcreatemultisig2.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "txid": "0d861f278a3b7bce7cb5a88d71e6e6a903336f95ad5a2c29b295b63835b6eee3",
- "hash": "0d861f278a3b7bce7cb5a88d71e6e6a903336f95ad5a2c29b295b63835b6eee3",
- "version": 1,
- "locktime": 0,
- "vin": [
- ],
- "vout": [
- {
- "value": 1.00,
- "n": 0,
- "scriptPubKey": {
- "asm": "OP_HASH160 1c6fbaf46d64221e80cbae182c33ddf81b9294ac OP_EQUAL",
- "hex": "a9141c6fbaf46d64221e80cbae182c33ddf81b9294ac87",
- "reqSigs": 1,
- "type": "scripthash",
- "addresses": [
- "34HNh57oBCRKkxNyjTuWAJkTbuGh6jg2Ms"
- ]
- }
- }
- ],
- "hex": "01000000000100e1f5050000000017a9141c6fbaf46d64221e80cbae182c33ddf81b9294ac8700000000"
-}
diff --git a/src/test/data/txcreatemultisig3.hex b/src/test/data/txcreatemultisig3.hex
deleted file mode 100644
index 8d34f28f87..0000000000
--- a/src/test/data/txcreatemultisig3.hex
+++ /dev/null
@@ -1 +0,0 @@
-01000000000100e1f50500000000220020e15a86a23178f433d514dbbce042e87d72662b8b5edcacfd2e37ab7a2d135f0500000000
diff --git a/src/test/data/txcreatemultisig3.json b/src/test/data/txcreatemultisig3.json
deleted file mode 100644
index 88e32bd310..0000000000
--- a/src/test/data/txcreatemultisig3.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "txid": "ccc552220b46a3b5140048b03395987ce4f0fa1ddf8c635bba1fa44e0f8c1d7f",
- "hash": "ccc552220b46a3b5140048b03395987ce4f0fa1ddf8c635bba1fa44e0f8c1d7f",
- "version": 1,
- "locktime": 0,
- "vin": [
- ],
- "vout": [
- {
- "value": 1.00,
- "n": 0,
- "scriptPubKey": {
- "asm": "0 e15a86a23178f433d514dbbce042e87d72662b8b5edcacfd2e37ab7a2d135f05",
- "hex": "0020e15a86a23178f433d514dbbce042e87d72662b8b5edcacfd2e37ab7a2d135f05",
- "type": "witness_v0_scripthash"
- }
- }
- ],
- "hex": "01000000000100e1f50500000000220020e15a86a23178f433d514dbbce042e87d72662b8b5edcacfd2e37ab7a2d135f0500000000"
-}
diff --git a/src/test/data/txcreatemultisig4.hex b/src/test/data/txcreatemultisig4.hex
deleted file mode 100644
index 7da54366c7..0000000000
--- a/src/test/data/txcreatemultisig4.hex
+++ /dev/null
@@ -1 +0,0 @@
-01000000000100e1f5050000000017a9146edf12858999f0dae74f9c692e6694ee3621b2ac8700000000
diff --git a/src/test/data/txcreatemultisig4.json b/src/test/data/txcreatemultisig4.json
deleted file mode 100644
index fc69c7269c..0000000000
--- a/src/test/data/txcreatemultisig4.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "txid": "5e8b1cc73234e208d4b7ca9075f136b908c34101be7a048df4ba9ac758b61567",
- "hash": "5e8b1cc73234e208d4b7ca9075f136b908c34101be7a048df4ba9ac758b61567",
- "version": 1,
- "locktime": 0,
- "vin": [
- ],
- "vout": [
- {
- "value": 1.00,
- "n": 0,
- "scriptPubKey": {
- "asm": "OP_HASH160 6edf12858999f0dae74f9c692e6694ee3621b2ac OP_EQUAL",
- "hex": "a9146edf12858999f0dae74f9c692e6694ee3621b2ac87",
- "reqSigs": 1,
- "type": "scripthash",
- "addresses": [
- "3BoFUz1StqcNcgUTZE5cC1eFhuYFzj3fGH"
- ]
- }
- }
- ],
- "hex": "01000000000100e1f5050000000017a9146edf12858999f0dae74f9c692e6694ee3621b2ac8700000000"
-}
diff --git a/src/test/data/txcreateoutpubkey1.hex b/src/test/data/txcreateoutpubkey1.hex
deleted file mode 100644
index 4a08244b2f..0000000000
--- a/src/test/data/txcreateoutpubkey1.hex
+++ /dev/null
@@ -1 +0,0 @@
-0100000000010000000000000000232102a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397ac00000000
diff --git a/src/test/data/txcreateoutpubkey1.json b/src/test/data/txcreateoutpubkey1.json
deleted file mode 100644
index 6019fa2dcd..0000000000
--- a/src/test/data/txcreateoutpubkey1.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "txid": "f42b38ac12e3fafc96ba1a9ba70cbfe326744aef75df5fb9db5d6e2855ca415f",
- "hash": "f42b38ac12e3fafc96ba1a9ba70cbfe326744aef75df5fb9db5d6e2855ca415f",
- "version": 1,
- "locktime": 0,
- "vin": [
- ],
- "vout": [
- {
- "value": 0.00,
- "n": 0,
- "scriptPubKey": {
- "asm": "02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397 OP_CHECKSIG",
- "hex": "2102a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397ac",
- "reqSigs": 1,
- "type": "pubkey",
- "addresses": [
- "1FoG2386FG2tAJS9acMuiDsKy67aGg9MKz"
- ]
- }
- }
- ],
- "hex": "0100000000010000000000000000232102a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397ac00000000"
-}
diff --git a/src/test/data/txcreateoutpubkey2.hex b/src/test/data/txcreateoutpubkey2.hex
deleted file mode 100644
index 8283c722ab..0000000000
--- a/src/test/data/txcreateoutpubkey2.hex
+++ /dev/null
@@ -1 +0,0 @@
-0100000000010000000000000000160014a2516e770582864a6a56ed21a102044e388c62e300000000
diff --git a/src/test/data/txcreateoutpubkey2.json b/src/test/data/txcreateoutpubkey2.json
deleted file mode 100644
index 6fc3d57527..0000000000
--- a/src/test/data/txcreateoutpubkey2.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "txid": "70f2a088cde460e677415fa1fb71895e90c231e6ed38ed203a35b6f848e9cc73",
- "hash": "70f2a088cde460e677415fa1fb71895e90c231e6ed38ed203a35b6f848e9cc73",
- "version": 1,
- "locktime": 0,
- "vin": [
- ],
- "vout": [
- {
- "value": 0.00,
- "n": 0,
- "scriptPubKey": {
- "asm": "0 a2516e770582864a6a56ed21a102044e388c62e3",
- "hex": "0014a2516e770582864a6a56ed21a102044e388c62e3",
- "type": "witness_v0_keyhash"
- }
- }
- ],
- "hex": "0100000000010000000000000000160014a2516e770582864a6a56ed21a102044e388c62e300000000"
-}
diff --git a/src/test/data/txcreateoutpubkey3.hex b/src/test/data/txcreateoutpubkey3.hex
deleted file mode 100644
index 84adff4d89..0000000000
--- a/src/test/data/txcreateoutpubkey3.hex
+++ /dev/null
@@ -1 +0,0 @@
-010000000001000000000000000017a914a5ab14c9804d0d8bf02f1aea4e82780733ad0a838700000000
diff --git a/src/test/data/txcreateoutpubkey3.json b/src/test/data/txcreateoutpubkey3.json
deleted file mode 100644
index a1a25fc834..0000000000
--- a/src/test/data/txcreateoutpubkey3.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "txid": "bfc7e898ee9f6a9652d7b8cca147e2da134502e2ada0f279ed634fc8cf833f8c",
- "hash": "bfc7e898ee9f6a9652d7b8cca147e2da134502e2ada0f279ed634fc8cf833f8c",
- "version": 1,
- "locktime": 0,
- "vin": [
- ],
- "vout": [
- {
- "value": 0.00,
- "n": 0,
- "scriptPubKey": {
- "asm": "OP_HASH160 a5ab14c9804d0d8bf02f1aea4e82780733ad0a83 OP_EQUAL",
- "hex": "a914a5ab14c9804d0d8bf02f1aea4e82780733ad0a8387",
- "reqSigs": 1,
- "type": "scripthash",
- "addresses": [
- "3GnzN8FqgvYGYdhj8NW6UNxxVv3Uj1ApQn"
- ]
- }
- }
- ],
- "hex": "010000000001000000000000000017a914a5ab14c9804d0d8bf02f1aea4e82780733ad0a838700000000"
-}
diff --git a/src/test/data/txcreatescript1.hex b/src/test/data/txcreatescript1.hex
deleted file mode 100644
index 0adce270fb..0000000000
--- a/src/test/data/txcreatescript1.hex
+++ /dev/null
@@ -1 +0,0 @@
-0100000000010000000000000000017500000000
diff --git a/src/test/data/txcreatescript1.json b/src/test/data/txcreatescript1.json
deleted file mode 100644
index 8ffecba411..0000000000
--- a/src/test/data/txcreatescript1.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "txid": "f0851b68202f736b792649cfc960259c2374badcb644ab20cac726b5f72f61c9",
- "hash": "f0851b68202f736b792649cfc960259c2374badcb644ab20cac726b5f72f61c9",
- "version": 1,
- "locktime": 0,
- "vin": [
- ],
- "vout": [
- {
- "value": 0.00,
- "n": 0,
- "scriptPubKey": {
- "asm": "OP_DROP",
- "hex": "75",
- "type": "nonstandard"
- }
- }
- ],
- "hex": "0100000000010000000000000000017500000000"
-}
diff --git a/src/test/data/txcreatescript2.hex b/src/test/data/txcreatescript2.hex
deleted file mode 100644
index 5afe8786e3..0000000000
--- a/src/test/data/txcreatescript2.hex
+++ /dev/null
@@ -1 +0,0 @@
-010000000001000000000000000017a91471ed53322d470bb96657deb786b94f97dd46fb158700000000
diff --git a/src/test/data/txcreatescript2.json b/src/test/data/txcreatescript2.json
deleted file mode 100644
index 41eb69f1af..0000000000
--- a/src/test/data/txcreatescript2.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "txid": "6e07a7cc075e0703f32ee8c4e5373fe654bfbc315148fda364e1be286ff290d0",
- "hash": "6e07a7cc075e0703f32ee8c4e5373fe654bfbc315148fda364e1be286ff290d0",
- "version": 1,
- "locktime": 0,
- "vin": [
- ],
- "vout": [
- {
- "value": 0.00,
- "n": 0,
- "scriptPubKey": {
- "asm": "OP_HASH160 71ed53322d470bb96657deb786b94f97dd46fb15 OP_EQUAL",
- "hex": "a91471ed53322d470bb96657deb786b94f97dd46fb1587",
- "reqSigs": 1,
- "type": "scripthash",
- "addresses": [
- "3C5QarEGh9feKbDJ3QbMf2YNjnMoiPDhNp"
- ]
- }
- }
- ],
- "hex": "010000000001000000000000000017a91471ed53322d470bb96657deb786b94f97dd46fb158700000000"
-}
diff --git a/src/test/data/txcreatescript3.hex b/src/test/data/txcreatescript3.hex
deleted file mode 100644
index 8a2b973bf0..0000000000
--- a/src/test/data/txcreatescript3.hex
+++ /dev/null
@@ -1 +0,0 @@
-01000000000100000000000000002200200bfe935e70c321c7ca3afc75ce0d0ca2f98b5422e008bb31c00c6d7f1f1c0ad600000000
diff --git a/src/test/data/txcreatescript3.json b/src/test/data/txcreatescript3.json
deleted file mode 100644
index 90e7e27f9f..0000000000
--- a/src/test/data/txcreatescript3.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "txid": "8a234037b088e987c877030efc83374a07441c321bf9dc6dd2f206bc26507df8",
- "hash": "8a234037b088e987c877030efc83374a07441c321bf9dc6dd2f206bc26507df8",
- "version": 1,
- "locktime": 0,
- "vin": [
- ],
- "vout": [
- {
- "value": 0.00,
- "n": 0,
- "scriptPubKey": {
- "asm": "0 0bfe935e70c321c7ca3afc75ce0d0ca2f98b5422e008bb31c00c6d7f1f1c0ad6",
- "hex": "00200bfe935e70c321c7ca3afc75ce0d0ca2f98b5422e008bb31c00c6d7f1f1c0ad6",
- "type": "witness_v0_scripthash"
- }
- }
- ],
- "hex": "01000000000100000000000000002200200bfe935e70c321c7ca3afc75ce0d0ca2f98b5422e008bb31c00c6d7f1f1c0ad600000000"
-}
diff --git a/src/test/data/txcreatescript4.hex b/src/test/data/txcreatescript4.hex
deleted file mode 100644
index b4cfe58f42..0000000000
--- a/src/test/data/txcreatescript4.hex
+++ /dev/null
@@ -1 +0,0 @@
-010000000001000000000000000017a9146a2c482f4985f57e702f325816c90e3723ca81ae8700000000
diff --git a/src/test/data/txcreatescript4.json b/src/test/data/txcreatescript4.json
deleted file mode 100644
index 11783751a4..0000000000
--- a/src/test/data/txcreatescript4.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "txid": "24225cf5e9391100d6b218134b9f03383ca4c880a1f634ac12990cf28b66adbc",
- "hash": "24225cf5e9391100d6b218134b9f03383ca4c880a1f634ac12990cf28b66adbc",
- "version": 1,
- "locktime": 0,
- "vin": [
- ],
- "vout": [
- {
- "value": 0.00,
- "n": 0,
- "scriptPubKey": {
- "asm": "OP_HASH160 6a2c482f4985f57e702f325816c90e3723ca81ae OP_EQUAL",
- "hex": "a9146a2c482f4985f57e702f325816c90e3723ca81ae87",
- "reqSigs": 1,
- "type": "scripthash",
- "addresses": [
- "3BNQbeFeJJGMAyDxPwWPuqxPMrjsFLjk3f"
- ]
- }
- }
- ],
- "hex": "010000000001000000000000000017a9146a2c482f4985f57e702f325816c90e3723ca81ae8700000000"
-}
diff --git a/src/test/data/txcreatesignv1.hex b/src/test/data/txcreatesignv1.hex
deleted file mode 100644
index a46fcc88cb..0000000000
--- a/src/test/data/txcreatesignv1.hex
+++ /dev/null
@@ -1 +0,0 @@
-01000000018594c5bdcaec8f06b78b596f31cd292a294fd031e24eec716f43dac91ea7494d000000008b48304502210096a75056c9e2cc62b7214777b3d2a592cfda7092520126d4ebfcd6d590c99bd8022051bb746359cf98c0603f3004477eac68701132380db8facba19c89dc5ab5c5e201410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ffffffff01a0860100000000001976a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac00000000
diff --git a/src/test/data/txcreatesignv1.json b/src/test/data/txcreatesignv1.json
deleted file mode 100644
index ff39e71b40..0000000000
--- a/src/test/data/txcreatesignv1.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "txid": "977e7cd286cb72cd470d539ba6cb48400f8f387d97451d45cdb8819437a303af",
- "hash": "977e7cd286cb72cd470d539ba6cb48400f8f387d97451d45cdb8819437a303af",
- "version": 1,
- "locktime": 0,
- "vin": [
- {
- "txid": "4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485",
- "vout": 0,
- "scriptSig": {
- "asm": "304502210096a75056c9e2cc62b7214777b3d2a592cfda7092520126d4ebfcd6d590c99bd8022051bb746359cf98c0603f3004477eac68701132380db8facba19c89dc5ab5c5e2[ALL] 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
- "hex": "48304502210096a75056c9e2cc62b7214777b3d2a592cfda7092520126d4ebfcd6d590c99bd8022051bb746359cf98c0603f3004477eac68701132380db8facba19c89dc5ab5c5e201410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"
- },
- "sequence": 4294967295
- }
- ],
- "vout": [
- {
- "value": 0.001,
- "n": 0,
- "scriptPubKey": {
- "asm": "OP_DUP OP_HASH160 5834479edbbe0539b31ffd3a8f8ebadc2165ed01 OP_EQUALVERIFY OP_CHECKSIG",
- "hex": "76a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac",
- "reqSigs": 1,
- "type": "pubkeyhash",
- "addresses": [
- "193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7"
- ]
- }
- }
- ],
- "hex": "01000000018594c5bdcaec8f06b78b596f31cd292a294fd031e24eec716f43dac91ea7494d000000008b48304502210096a75056c9e2cc62b7214777b3d2a592cfda7092520126d4ebfcd6d590c99bd8022051bb746359cf98c0603f3004477eac68701132380db8facba19c89dc5ab5c5e201410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ffffffff01a0860100000000001976a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac00000000"
-}
diff --git a/src/test/data/txcreatesignv2.hex b/src/test/data/txcreatesignv2.hex
deleted file mode 100644
index ee425cd98c..0000000000
--- a/src/test/data/txcreatesignv2.hex
+++ /dev/null
@@ -1 +0,0 @@
-02000000018594c5bdcaec8f06b78b596f31cd292a294fd031e24eec716f43dac91ea7494d000000008a473044022079c7aa014177a2e973caf6df7c7b8f15399083b91eba370ea1e19c4caed9181e02205f8f8763505ce8e6cbdd2cd28fab3fd407a75003e7d0dc04e6bebb0a3c89e7cb01410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ffffffff01a0860100000000001976a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac00000000
diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp
index e5cb48ffcf..efddafe17e 100644
--- a/src/test/dbwrapper_tests.cpp
+++ b/src/test/dbwrapper_tests.cpp
@@ -7,8 +7,6 @@
#include "random.h"
#include "test/test_bitcoin.h"
-#include <boost/assign/std/vector.hpp> // for 'operator+=()'
-#include <boost/assert.hpp>
#include <boost/test/unit_test.hpp>
// Test if a string consists entirely of null characters
@@ -26,12 +24,11 @@ BOOST_FIXTURE_TEST_SUITE(dbwrapper_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(dbwrapper)
{
// Perform tests both obfuscated and non-obfuscated.
- for (int i = 0; i < 2; i++) {
- bool obfuscate = (bool)i;
- boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
+ for (bool obfuscate : {false, true}) {
+ fs::path ph = fs::temp_directory_path() / fs::unique_path();
CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
char key = 'k';
- uint256 in = GetRandHash();
+ uint256 in = InsecureRand256();
uint256 res;
// Ensure that we're doing real obfuscation when obfuscate=true
@@ -47,17 +44,16 @@ BOOST_AUTO_TEST_CASE(dbwrapper)
BOOST_AUTO_TEST_CASE(dbwrapper_batch)
{
// Perform tests both obfuscated and non-obfuscated.
- for (int i = 0; i < 2; i++) {
- bool obfuscate = (bool)i;
- boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
+ for (bool obfuscate : {false, true}) {
+ fs::path ph = fs::temp_directory_path() / fs::unique_path();
CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
char key = 'i';
- uint256 in = GetRandHash();
+ uint256 in = InsecureRand256();
char key2 = 'j';
- uint256 in2 = GetRandHash();
+ uint256 in2 = InsecureRand256();
char key3 = 'k';
- uint256 in3 = GetRandHash();
+ uint256 in3 = InsecureRand256();
uint256 res;
CDBBatch batch(dbw);
@@ -76,7 +72,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_batch)
BOOST_CHECK(dbw.Read(key2, res));
BOOST_CHECK_EQUAL(res.ToString(), in2.ToString());
- // key3 never should've been written
+ // key3 should've never been written
BOOST_CHECK(dbw.Read(key3, res) == false);
}
}
@@ -84,20 +80,19 @@ BOOST_AUTO_TEST_CASE(dbwrapper_batch)
BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
{
// Perform tests both obfuscated and non-obfuscated.
- for (int i = 0; i < 2; i++) {
- bool obfuscate = (bool)i;
- boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
+ for (bool obfuscate : {false, true}) {
+ fs::path ph = fs::temp_directory_path() / fs::unique_path();
CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
// The two keys are intentionally chosen for ordering
char key = 'j';
- uint256 in = GetRandHash();
+ uint256 in = InsecureRand256();
BOOST_CHECK(dbw.Write(key, in));
char key2 = 'k';
- uint256 in2 = GetRandHash();
+ uint256 in2 = InsecureRand256();
BOOST_CHECK(dbw.Write(key2, in2));
- std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
+ std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper&>(dbw).NewIterator());
// Be sure to seek past the obfuscation key (if it exists)
it->Seek(key);
@@ -125,14 +120,14 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
// Test that we do not obfuscation if there is existing data.
BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
{
- // We're going to share this boost::filesystem::path between two wrappers
- boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
+ // We're going to share this fs::path between two wrappers
+ fs::path ph = fs::temp_directory_path() / fs::unique_path();
create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data.
CDBWrapper* dbw = new CDBWrapper(ph, (1 << 10), false, false, false);
char key = 'k';
- uint256 in = GetRandHash();
+ uint256 in = InsecureRand256();
uint256 res;
BOOST_CHECK(dbw->Write(key, in));
@@ -141,6 +136,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
// Call the destructor to free leveldb LOCK
delete dbw;
+ dbw = nullptr;
// Now, set up another wrapper that wants to obfuscate the same directory
CDBWrapper odbw(ph, (1 << 10), false, false, true);
@@ -154,7 +150,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
BOOST_CHECK(!odbw.IsEmpty()); // There should be existing data
BOOST_CHECK(is_null_key(dbwrapper_private::GetObfuscateKey(odbw))); // The key should be an empty string
- uint256 in2 = GetRandHash();
+ uint256 in2 = InsecureRand256();
uint256 res3;
// Check that we can write successfully
@@ -166,14 +162,14 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
// Ensure that we start obfuscating during a reindex.
BOOST_AUTO_TEST_CASE(existing_data_reindex)
{
- // We're going to share this boost::filesystem::path between two wrappers
- boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
+ // We're going to share this fs::path between two wrappers
+ fs::path ph = fs::temp_directory_path() / fs::unique_path();
create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data.
CDBWrapper* dbw = new CDBWrapper(ph, (1 << 10), false, false, false);
char key = 'k';
- uint256 in = GetRandHash();
+ uint256 in = InsecureRand256();
uint256 res;
BOOST_CHECK(dbw->Write(key, in));
@@ -182,6 +178,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex)
// Call the destructor to free leveldb LOCK
delete dbw;
+ dbw = nullptr;
// Simulate a -reindex by wiping the existing data store
CDBWrapper odbw(ph, (1 << 10), false, true, true);
@@ -191,7 +188,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex)
BOOST_CHECK(!odbw.Read(key, res2));
BOOST_CHECK(!is_null_key(dbwrapper_private::GetObfuscateKey(odbw)));
- uint256 in2 = GetRandHash();
+ uint256 in2 = InsecureRand256();
uint256 res3;
// Check that we can write successfully
@@ -202,29 +199,36 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex)
BOOST_AUTO_TEST_CASE(iterator_ordering)
{
- boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
+ fs::path ph = fs::temp_directory_path() / fs::unique_path();
CDBWrapper dbw(ph, (1 << 20), true, false, false);
for (int x=0x00; x<256; ++x) {
uint8_t key = x;
uint32_t value = x*x;
- BOOST_CHECK(dbw.Write(key, value));
+ if (!(x & 1)) BOOST_CHECK(dbw.Write(key, value));
}
- std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
- for (int c=0; c<2; ++c) {
- int seek_start;
- if (c == 0)
- seek_start = 0x00;
- else
- seek_start = 0x80;
+ // Check that creating an iterator creates a snapshot
+ std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper&>(dbw).NewIterator());
+
+ for (int x=0x00; x<256; ++x) {
+ uint8_t key = x;
+ uint32_t value = x*x;
+ if (x & 1) BOOST_CHECK(dbw.Write(key, value));
+ }
+
+ for (int seek_start : {0x00, 0x80}) {
it->Seek((uint8_t)seek_start);
- for (int x=seek_start; x<256; ++x) {
+ for (int x=seek_start; x<255; ++x) {
uint8_t key;
uint32_t value;
BOOST_CHECK(it->Valid());
if (!it->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure
break;
BOOST_CHECK(it->GetKey(key));
+ if (x & 1) {
+ BOOST_CHECK_EQUAL(key, x + 1);
+ continue;
+ }
BOOST_CHECK(it->GetValue(value));
BOOST_CHECK_EQUAL(key, x);
BOOST_CHECK_EQUAL(value, x*x);
@@ -239,7 +243,7 @@ struct StringContentsSerializer {
// This is a terrible idea
std::string str;
StringContentsSerializer() {}
- StringContentsSerializer(const std::string& inp) : str(inp) {}
+ explicit StringContentsSerializer(const std::string& inp) : str(inp) {}
StringContentsSerializer& operator+=(const std::string& s) {
str += s;
@@ -273,11 +277,11 @@ BOOST_AUTO_TEST_CASE(iterator_string_ordering)
{
char buf[10];
- boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
+ fs::path ph = fs::temp_directory_path() / fs::unique_path();
CDBWrapper dbw(ph, (1 << 20), true, false, false);
for (int x=0x00; x<10; ++x) {
for (int y = 0; y < 10; y++) {
- sprintf(buf, "%d", x);
+ snprintf(buf, sizeof(buf), "%d", x);
StringContentsSerializer key(buf);
for (int z = 0; z < y; z++)
key += key;
@@ -286,19 +290,14 @@ BOOST_AUTO_TEST_CASE(iterator_string_ordering)
}
}
- std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
- for (int c=0; c<2; ++c) {
- int seek_start;
- if (c == 0)
- seek_start = 0;
- else
- seek_start = 5;
- sprintf(buf, "%d", seek_start);
+ std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper&>(dbw).NewIterator());
+ for (int seek_start : {0, 5}) {
+ snprintf(buf, sizeof(buf), "%d", seek_start);
StringContentsSerializer seek_key(buf);
it->Seek(seek_key);
for (int x=seek_start; x<10; ++x) {
for (int y = 0; y < 10; y++) {
- sprintf(buf, "%d", x);
+ snprintf(buf, sizeof(buf), "%d", x);
std::string exp_key(buf);
for (int z = 0; z < y; z++)
exp_key += exp_key;
diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp
index 9f59de3ef5..40f0ecd5f1 100644
--- a/src/test/getarg_tests.cpp
+++ b/src/test/getarg_tests.cpp
@@ -9,7 +9,6 @@
#include <vector>
#include <boost/algorithm/string.hpp>
-#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
BOOST_FIXTURE_TEST_SUITE(getarg_tests, BasicTestingSetup)
@@ -25,138 +24,138 @@ static void ResetArgs(const std::string& strArg)
// Convert to char*:
std::vector<const char*> vecChar;
- BOOST_FOREACH(std::string& s, vecArg)
+ for (std::string& s : vecArg)
vecChar.push_back(s.c_str());
- ParseParameters(vecChar.size(), &vecChar[0]);
+ gArgs.ParseParameters(vecChar.size(), vecChar.data());
}
BOOST_AUTO_TEST_CASE(boolarg)
{
ResetArgs("-foo");
- BOOST_CHECK(GetBoolArg("-foo", false));
- BOOST_CHECK(GetBoolArg("-foo", true));
+ BOOST_CHECK(gArgs.GetBoolArg("-foo", false));
+ BOOST_CHECK(gArgs.GetBoolArg("-foo", true));
- BOOST_CHECK(!GetBoolArg("-fo", false));
- BOOST_CHECK(GetBoolArg("-fo", true));
+ BOOST_CHECK(!gArgs.GetBoolArg("-fo", false));
+ BOOST_CHECK(gArgs.GetBoolArg("-fo", true));
- BOOST_CHECK(!GetBoolArg("-fooo", false));
- BOOST_CHECK(GetBoolArg("-fooo", true));
+ BOOST_CHECK(!gArgs.GetBoolArg("-fooo", false));
+ BOOST_CHECK(gArgs.GetBoolArg("-fooo", true));
ResetArgs("-foo=0");
- BOOST_CHECK(!GetBoolArg("-foo", false));
- BOOST_CHECK(!GetBoolArg("-foo", true));
+ BOOST_CHECK(!gArgs.GetBoolArg("-foo", false));
+ BOOST_CHECK(!gArgs.GetBoolArg("-foo", true));
ResetArgs("-foo=1");
- BOOST_CHECK(GetBoolArg("-foo", false));
- BOOST_CHECK(GetBoolArg("-foo", true));
+ BOOST_CHECK(gArgs.GetBoolArg("-foo", false));
+ BOOST_CHECK(gArgs.GetBoolArg("-foo", true));
// New 0.6 feature: auto-map -nosomething to !-something:
ResetArgs("-nofoo");
- BOOST_CHECK(!GetBoolArg("-foo", false));
- BOOST_CHECK(!GetBoolArg("-foo", true));
+ BOOST_CHECK(!gArgs.GetBoolArg("-foo", false));
+ BOOST_CHECK(!gArgs.GetBoolArg("-foo", true));
ResetArgs("-nofoo=1");
- BOOST_CHECK(!GetBoolArg("-foo", false));
- BOOST_CHECK(!GetBoolArg("-foo", true));
+ BOOST_CHECK(!gArgs.GetBoolArg("-foo", false));
+ BOOST_CHECK(!gArgs.GetBoolArg("-foo", true));
ResetArgs("-foo -nofoo"); // -nofoo should win
- BOOST_CHECK(!GetBoolArg("-foo", false));
- BOOST_CHECK(!GetBoolArg("-foo", true));
+ BOOST_CHECK(!gArgs.GetBoolArg("-foo", false));
+ BOOST_CHECK(!gArgs.GetBoolArg("-foo", true));
ResetArgs("-foo=1 -nofoo=1"); // -nofoo should win
- BOOST_CHECK(!GetBoolArg("-foo", false));
- BOOST_CHECK(!GetBoolArg("-foo", true));
+ BOOST_CHECK(!gArgs.GetBoolArg("-foo", false));
+ BOOST_CHECK(!gArgs.GetBoolArg("-foo", true));
ResetArgs("-foo=0 -nofoo=0"); // -nofoo=0 should win
- BOOST_CHECK(GetBoolArg("-foo", false));
- BOOST_CHECK(GetBoolArg("-foo", true));
+ BOOST_CHECK(gArgs.GetBoolArg("-foo", false));
+ BOOST_CHECK(gArgs.GetBoolArg("-foo", true));
// New 0.6 feature: treat -- same as -:
ResetArgs("--foo=1");
- BOOST_CHECK(GetBoolArg("-foo", false));
- BOOST_CHECK(GetBoolArg("-foo", true));
+ BOOST_CHECK(gArgs.GetBoolArg("-foo", false));
+ BOOST_CHECK(gArgs.GetBoolArg("-foo", true));
ResetArgs("--nofoo=1");
- BOOST_CHECK(!GetBoolArg("-foo", false));
- BOOST_CHECK(!GetBoolArg("-foo", true));
+ BOOST_CHECK(!gArgs.GetBoolArg("-foo", false));
+ BOOST_CHECK(!gArgs.GetBoolArg("-foo", true));
}
BOOST_AUTO_TEST_CASE(stringarg)
{
ResetArgs("");
- BOOST_CHECK_EQUAL(GetArg("-foo", ""), "");
- BOOST_CHECK_EQUAL(GetArg("-foo", "eleven"), "eleven");
+ BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", ""), "");
+ BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", "eleven"), "eleven");
ResetArgs("-foo -bar");
- BOOST_CHECK_EQUAL(GetArg("-foo", ""), "");
- BOOST_CHECK_EQUAL(GetArg("-foo", "eleven"), "");
+ BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", ""), "");
+ BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", "eleven"), "");
ResetArgs("-foo=");
- BOOST_CHECK_EQUAL(GetArg("-foo", ""), "");
- BOOST_CHECK_EQUAL(GetArg("-foo", "eleven"), "");
+ BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", ""), "");
+ BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", "eleven"), "");
ResetArgs("-foo=11");
- BOOST_CHECK_EQUAL(GetArg("-foo", ""), "11");
- BOOST_CHECK_EQUAL(GetArg("-foo", "eleven"), "11");
+ BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", ""), "11");
+ BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", "eleven"), "11");
ResetArgs("-foo=eleven");
- BOOST_CHECK_EQUAL(GetArg("-foo", ""), "eleven");
- BOOST_CHECK_EQUAL(GetArg("-foo", "eleven"), "eleven");
+ BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", ""), "eleven");
+ BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", "eleven"), "eleven");
}
BOOST_AUTO_TEST_CASE(intarg)
{
ResetArgs("");
- BOOST_CHECK_EQUAL(GetArg("-foo", 11), 11);
- BOOST_CHECK_EQUAL(GetArg("-foo", 0), 0);
+ BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", 11), 11);
+ BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", 0), 0);
ResetArgs("-foo -bar");
- BOOST_CHECK_EQUAL(GetArg("-foo", 11), 0);
- BOOST_CHECK_EQUAL(GetArg("-bar", 11), 0);
+ BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", 11), 0);
+ BOOST_CHECK_EQUAL(gArgs.GetArg("-bar", 11), 0);
ResetArgs("-foo=11 -bar=12");
- BOOST_CHECK_EQUAL(GetArg("-foo", 0), 11);
- BOOST_CHECK_EQUAL(GetArg("-bar", 11), 12);
+ BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", 0), 11);
+ BOOST_CHECK_EQUAL(gArgs.GetArg("-bar", 11), 12);
ResetArgs("-foo=NaN -bar=NotANumber");
- BOOST_CHECK_EQUAL(GetArg("-foo", 1), 0);
- BOOST_CHECK_EQUAL(GetArg("-bar", 11), 0);
+ BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", 1), 0);
+ BOOST_CHECK_EQUAL(gArgs.GetArg("-bar", 11), 0);
}
BOOST_AUTO_TEST_CASE(doubledash)
{
ResetArgs("--foo");
- BOOST_CHECK_EQUAL(GetBoolArg("-foo", false), true);
+ BOOST_CHECK_EQUAL(gArgs.GetBoolArg("-foo", false), true);
ResetArgs("--foo=verbose --bar=1");
- BOOST_CHECK_EQUAL(GetArg("-foo", ""), "verbose");
- BOOST_CHECK_EQUAL(GetArg("-bar", 0), 1);
+ BOOST_CHECK_EQUAL(gArgs.GetArg("-foo", ""), "verbose");
+ BOOST_CHECK_EQUAL(gArgs.GetArg("-bar", 0), 1);
}
BOOST_AUTO_TEST_CASE(boolargno)
{
ResetArgs("-nofoo");
- BOOST_CHECK(!GetBoolArg("-foo", true));
- BOOST_CHECK(!GetBoolArg("-foo", false));
+ BOOST_CHECK(!gArgs.GetBoolArg("-foo", true));
+ BOOST_CHECK(!gArgs.GetBoolArg("-foo", false));
ResetArgs("-nofoo=1");
- BOOST_CHECK(!GetBoolArg("-foo", true));
- BOOST_CHECK(!GetBoolArg("-foo", false));
+ BOOST_CHECK(!gArgs.GetBoolArg("-foo", true));
+ BOOST_CHECK(!gArgs.GetBoolArg("-foo", false));
ResetArgs("-nofoo=0");
- BOOST_CHECK(GetBoolArg("-foo", true));
- BOOST_CHECK(GetBoolArg("-foo", false));
+ BOOST_CHECK(gArgs.GetBoolArg("-foo", true));
+ BOOST_CHECK(gArgs.GetBoolArg("-foo", false));
ResetArgs("-foo --nofoo"); // --nofoo should win
- BOOST_CHECK(!GetBoolArg("-foo", true));
- BOOST_CHECK(!GetBoolArg("-foo", false));
+ BOOST_CHECK(!gArgs.GetBoolArg("-foo", true));
+ BOOST_CHECK(!gArgs.GetBoolArg("-foo", false));
ResetArgs("-nofoo -foo"); // foo always wins:
- BOOST_CHECK(GetBoolArg("-foo", true));
- BOOST_CHECK(GetBoolArg("-foo", false));
+ BOOST_CHECK(gArgs.GetBoolArg("-foo", true));
+ BOOST_CHECK(gArgs.GetBoolArg("-foo", false));
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp
index d8de765db1..05b6b3b1e6 100644
--- a/src/test/hash_tests.cpp
+++ b/src/test/hash_tests.cpp
@@ -128,6 +128,23 @@ BOOST_AUTO_TEST_CASE(siphash)
tx.nVersion = 1;
ss << tx;
BOOST_CHECK_EQUAL(SipHashUint256(1, 2, ss.GetHash()), 0x79751e980c2a0a35ULL);
+
+ // Check consistency between CSipHasher and SipHashUint256[Extra].
+ FastRandomContext ctx;
+ for (int i = 0; i < 16; ++i) {
+ uint64_t k1 = ctx.rand64();
+ uint64_t k2 = ctx.rand64();
+ uint256 x = InsecureRand256();
+ uint32_t n = ctx.rand32();
+ uint8_t nb[4];
+ WriteLE32(nb, n);
+ CSipHasher sip256(k1, k2);
+ sip256.Write(x.begin(), 32);
+ CSipHasher sip288 = sip256;
+ sip288.Write(nb, 4);
+ BOOST_CHECK_EQUAL(SipHashUint256(k1, k2, x), sip256.Finalize());
+ BOOST_CHECK_EQUAL(SipHashUint256Extra(k1, k2, x, n), sip288.Finalize());
+ }
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp
index 40a7fdf11d..91c0175412 100644
--- a/src/test/key_tests.cpp
+++ b/src/test/key_tests.cpp
@@ -16,45 +16,16 @@
#include <boost/test/unit_test.hpp>
-static const std::string strSecret1 ("5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj");
-static const std::string strSecret2 ("5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3");
-static const std::string strSecret1C ("Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw");
-static const std::string strSecret2C ("L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g");
-static const CBitcoinAddress addr1 ("1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ");
-static const CBitcoinAddress addr2 ("1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ");
-static const CBitcoinAddress addr1C("1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs");
-static const CBitcoinAddress addr2C("1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs");
+static const std::string strSecret1 = "5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj";
+static const std::string strSecret2 = "5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3";
+static const std::string strSecret1C = "Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw";
+static const std::string strSecret2C = "L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g";
+static const std::string addr1 = "1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ";
+static const std::string addr2 = "1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ";
+static const std::string addr1C = "1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs";
+static const std::string addr2C = "1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs";
-
-static const std::string strAddressBad("1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF");
-
-
-#ifdef KEY_TESTS_DUMPINFO
-void dumpKeyInfo(uint256 privkey)
-{
- CKey key;
- key.resize(32);
- memcpy(&secret[0], &privkey, 32);
- std::vector<unsigned char> sec;
- sec.resize(32);
- memcpy(&sec[0], &secret[0], 32);
- printf(" * secret (hex): %s\n", HexStr(sec).c_str());
-
- for (int nCompressed=0; nCompressed<2; nCompressed++)
- {
- bool fCompressed = nCompressed == 1;
- printf(" * %s:\n", fCompressed ? "compressed" : "uncompressed");
- CBitcoinSecret bsecret;
- bsecret.SetSecret(secret, fCompressed);
- printf(" * secret (base58): %s\n", bsecret.ToString().c_str());
- CKey key;
- key.SetSecret(secret, fCompressed);
- std::vector<unsigned char> vchPubKey = key.GetPubKey();
- printf(" * pubkey (hex): %s\n", HexStr(vchPubKey).c_str());
- printf(" * address (base58): %s\n", CBitcoinAddress(vchPubKey).ToString().c_str());
- }
-}
-#endif
+static const std::string strAddressBad = "1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF";
BOOST_FIXTURE_TEST_SUITE(key_tests, BasicTestingSetup)
@@ -102,10 +73,10 @@ BOOST_AUTO_TEST_CASE(key_test1)
BOOST_CHECK(!key2C.VerifyPubKey(pubkey2));
BOOST_CHECK(key2C.VerifyPubKey(pubkey2C));
- BOOST_CHECK(addr1.Get() == CTxDestination(pubkey1.GetID()));
- BOOST_CHECK(addr2.Get() == CTxDestination(pubkey2.GetID()));
- BOOST_CHECK(addr1C.Get() == CTxDestination(pubkey1C.GetID()));
- BOOST_CHECK(addr2C.Get() == CTxDestination(pubkey2C.GetID()));
+ BOOST_CHECK(DecodeDestination(addr1) == CTxDestination(pubkey1.GetID()));
+ BOOST_CHECK(DecodeDestination(addr2) == CTxDestination(pubkey2.GetID()));
+ BOOST_CHECK(DecodeDestination(addr1C) == CTxDestination(pubkey1C.GetID()));
+ BOOST_CHECK(DecodeDestination(addr2C) == CTxDestination(pubkey2C.GetID()));
for (int n=0; n<16; n++)
{
diff --git a/src/test/limitedmap_tests.cpp b/src/test/limitedmap_tests.cpp
index 55b9be5b00..b071ab117b 100644
--- a/src/test/limitedmap_tests.cpp
+++ b/src/test/limitedmap_tests.cpp
@@ -27,7 +27,7 @@ BOOST_AUTO_TEST_CASE(limitedmap_test)
// make sure that the size is updated
BOOST_CHECK(map.size() == 1);
- // make sure that the new items is in the map
+ // make sure that the new item is in the map
BOOST_CHECK(map.count(-1) == 1);
// insert 10 new items
diff --git a/src/test/main_tests.cpp b/src/test/main_tests.cpp
index d52104b4cc..656aec606b 100644
--- a/src/test/main_tests.cpp
+++ b/src/test/main_tests.cpp
@@ -39,17 +39,18 @@ static void TestBlockSubsidyHalvings(int nSubsidyHalvingInterval)
BOOST_AUTO_TEST_CASE(block_subsidy_test)
{
- TestBlockSubsidyHalvings(Params(CBaseChainParams::MAIN).GetConsensus()); // As in main
+ const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);
+ TestBlockSubsidyHalvings(chainParams->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();
+ const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);
CAmount nSum = 0;
for (int nHeight = 0; nHeight < 14000000; nHeight += 1000) {
- CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams);
+ CAmount nSubsidy = GetBlockSubsidy(nHeight, chainParams->GetConsensus());
BOOST_CHECK(nSubsidy <= 50 * COIN);
nSum += nSubsidy * 1000;
BOOST_CHECK(MoneyRange(nSum));
diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp
index 91f549fe48..116210a297 100644
--- a/src/test/mempool_tests.cpp
+++ b/src/test/mempool_tests.cpp
@@ -54,7 +54,7 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
}
- CTxMemPool testPool(CFeeRate(0));
+ CTxMemPool testPool;
// Nothing in pool, remove should do nothing:
unsigned int poolSize = testPool.size();
@@ -118,7 +118,7 @@ void CheckSort(CTxMemPool &pool, std::vector<std::string> &sortedOrder)
BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
{
- CTxMemPool pool(CFeeRate(0));
+ CTxMemPool pool;
TestMemPoolEntryHelper entry;
/* 3rd highest fee */
@@ -126,28 +126,28 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
tx1.vout.resize(1);
tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx1.vout[0].nValue = 10 * COIN;
- pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).Priority(10.0).FromTx(tx1));
+ pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1));
/* 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(), entry.Fee(20000LL).Priority(9.0).FromTx(tx2));
+ pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).FromTx(tx2));
/* 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(), entry.Fee(0LL).Priority(100.0).FromTx(tx3));
+ pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).FromTx(tx3));
/* 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(), entry.Fee(15000LL).Priority(1.0).FromTx(tx4));
+ pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).FromTx(tx4));
/* equal fee rate to tx1, but newer */
CMutableTransaction tx5 = CMutableTransaction();
@@ -155,7 +155,6 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx5.vout[0].nValue = 11 * COIN;
entry.nTime = 1;
- entry.dPriority = 10.0;
pool.addUnchecked(tx5.GetHash(), entry.Fee(10000LL).FromTx(tx5));
BOOST_CHECK_EQUAL(pool.size(), 5);
@@ -320,7 +319,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
{
- CTxMemPool pool(CFeeRate(0));
+ CTxMemPool pool;
TestMemPoolEntryHelper entry;
/* 3rd highest fee */
@@ -328,14 +327,14 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
tx1.vout.resize(1);
tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx1.vout[0].nValue = 10 * COIN;
- pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).Priority(10.0).FromTx(tx1));
+ pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1));
/* 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(), entry.Fee(20000LL).Priority(9.0).FromTx(tx2));
+ pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).FromTx(tx2));
uint64_t tx2Size = GetVirtualTransactionSize(tx2);
/* lowest fee */
@@ -343,14 +342,14 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
tx3.vout.resize(1);
tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx3.vout[0].nValue = 5 * COIN;
- pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).Priority(100.0).FromTx(tx3));
+ pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).FromTx(tx3));
/* 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(), entry.Fee(15000LL).Priority(1.0).FromTx(tx4));
+ pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).FromTx(tx4));
/* equal fee rate to tx1, but newer */
CMutableTransaction tx5 = CMutableTransaction();
@@ -408,7 +407,6 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
/* set the fee to just below tx2's feerate when including ancestor */
CAmount fee = (20000/tx2Size)*(tx7Size + tx6Size) - 1;
- //CTxMemPoolEntry entry7(tx7, fee, 2, 10.0, 1, true);
pool.addUnchecked(tx7.GetHash(), entry.Fee(fee).FromTx(tx7));
BOOST_CHECK_EQUAL(pool.size(), 7);
sortedOrder.insert(sortedOrder.begin()+1, tx7.GetHash().ToString());
@@ -432,9 +430,8 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
{
- CTxMemPool pool(CFeeRate(1000));
+ CTxMemPool pool;
TestMemPoolEntryHelper entry;
- entry.dPriority = 10.0;
CMutableTransaction tx1 = CMutableTransaction();
tx1.vin.resize(1);
@@ -442,7 +439,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
tx1.vout.resize(1);
tx1.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL;
tx1.vout[0].nValue = 10 * COIN;
- pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1, &pool));
+ pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1));
CMutableTransaction tx2 = CMutableTransaction();
tx2.vin.resize(1);
@@ -450,7 +447,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
tx2.vout.resize(1);
tx2.vout[0].scriptPubKey = CScript() << OP_2 << OP_EQUAL;
tx2.vout[0].nValue = 10 * COIN;
- pool.addUnchecked(tx2.GetHash(), entry.Fee(5000LL).FromTx(tx2, &pool));
+ pool.addUnchecked(tx2.GetHash(), entry.Fee(5000LL).FromTx(tx2));
pool.TrimToSize(pool.DynamicMemoryUsage()); // should do nothing
BOOST_CHECK(pool.exists(tx1.GetHash()));
@@ -460,7 +457,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
BOOST_CHECK(pool.exists(tx1.GetHash()));
BOOST_CHECK(!pool.exists(tx2.GetHash()));
- pool.addUnchecked(tx2.GetHash(), entry.FromTx(tx2, &pool));
+ pool.addUnchecked(tx2.GetHash(), entry.FromTx(tx2));
CMutableTransaction tx3 = CMutableTransaction();
tx3.vin.resize(1);
tx3.vin[0].prevout = COutPoint(tx2.GetHash(), 0);
@@ -468,7 +465,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
tx3.vout.resize(1);
tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL;
tx3.vout[0].nValue = 10 * COIN;
- pool.addUnchecked(tx3.GetHash(), entry.Fee(20000LL).FromTx(tx3, &pool));
+ pool.addUnchecked(tx3.GetHash(), entry.Fee(20000LL).FromTx(tx3));
pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // tx3 should pay for tx2 (CPFP)
BOOST_CHECK(!pool.exists(tx1.GetHash()));
@@ -531,10 +528,10 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
tx7.vout[1].nValue = 10 * COIN;
- pool.addUnchecked(tx4.GetHash(), entry.Fee(7000LL).FromTx(tx4, &pool));
- pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5, &pool));
- pool.addUnchecked(tx6.GetHash(), entry.Fee(1100LL).FromTx(tx6, &pool));
- pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool));
+ pool.addUnchecked(tx4.GetHash(), entry.Fee(7000LL).FromTx(tx4));
+ pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5));
+ pool.addUnchecked(tx6.GetHash(), entry.Fee(1100LL).FromTx(tx6));
+ pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7));
// we only require this remove, at max, 2 txn, because its not clear what we're really optimizing for aside from that
pool.TrimToSize(pool.DynamicMemoryUsage() - 1);
@@ -543,8 +540,8 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
BOOST_CHECK(!pool.exists(tx7.GetHash()));
if (!pool.exists(tx5.GetHash()))
- pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5, &pool));
- pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool));
+ pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5));
+ pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7));
pool.TrimToSize(pool.DynamicMemoryUsage() / 2); // should maximize mempool size by only removing 5/7
BOOST_CHECK(pool.exists(tx4.GetHash()));
@@ -552,8 +549,8 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
BOOST_CHECK(pool.exists(tx6.GetHash()));
BOOST_CHECK(!pool.exists(tx7.GetHash()));
- pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5, &pool));
- pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool));
+ pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5));
+ pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7));
std::vector<CTransactionRef> vtx;
SetMockTime(42);
@@ -562,15 +559,15 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
// ... we should keep the same min fee until we get a block
pool.removeForBlock(vtx, 1);
SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE);
- BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000)/2);
+ BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + 1000)/2.0));
// ... then feerate should drop 1/2 each halflife
SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2);
- BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 5 / 2).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000)/4);
+ BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 5 / 2).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + 1000)/4.0));
// ... with a 1/2 halflife when mempool is < 1/2 its target size
SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4);
- BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 9 / 2).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000)/8);
+ BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 9 / 2).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + 1000)/8.0));
// ... with a 1/4 halflife when mempool is < 1/4 its target size
SetMockTime(42 + 7*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4);
diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp
index af02d67f74..1a1cf4399c 100644
--- a/src/test/merkle_tests.cpp
+++ b/src/test/merkle_tests.cpp
@@ -4,7 +4,6 @@
#include "consensus/merkle.h"
#include "test/test_bitcoin.h"
-#include "test/test_random.h"
#include <boost/test/unit_test.hpp>
@@ -68,7 +67,7 @@ BOOST_AUTO_TEST_CASE(merkle_test)
{
for (int i = 0; i < 32; i++) {
// Try 32 block sizes: all sizes from 0 to 16 inclusive, and then 15 random sizes.
- int ntx = (i <= 16) ? i : 17 + (insecure_rand() % 4000);
+ int ntx = (i <= 16) ? i : 17 + (InsecureRandRange(4000));
// Try up to 3 mutations.
for (int mutate = 0; mutate <= 3; mutate++) {
int duplicate1 = mutate >= 1 ? 1 << ctz(ntx) : 0; // The last how many transactions to duplicate first.
@@ -118,10 +117,10 @@ BOOST_AUTO_TEST_CASE(merkle_test)
// If no mutation was done (once for every ntx value), try up to 16 branches.
if (mutate == 0) {
for (int loop = 0; loop < std::min(ntx, 16); loop++) {
- // If ntx <= 16, try all branches. Otherise, try 16 random ones.
+ // If ntx <= 16, try all branches. Otherwise, try 16 random ones.
int mtx = loop;
if (ntx > 16) {
- mtx = insecure_rand() % ntx;
+ mtx = InsecureRandRange(ntx);
}
std::vector<uint256> newBranch = BlockMerkleBranch(block, mtx);
std::vector<uint256> oldBranch = BlockGetMerkleBranch(block, merkleTree, mtx);
diff --git a/src/test/merkleblock_tests.cpp b/src/test/merkleblock_tests.cpp
new file mode 100644
index 0000000000..3e66c6f2c6
--- /dev/null
+++ b/src/test/merkleblock_tests.cpp
@@ -0,0 +1,78 @@
+// Copyright (c) 2012-2017 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 "merkleblock.h"
+#include "uint256.h"
+#include "test/test_bitcoin.h"
+
+#include <boost/test/unit_test.hpp>
+
+
+BOOST_FIXTURE_TEST_SUITE(merkleblock_tests, BasicTestingSetup)
+
+/**
+ * Create a CMerkleBlock using a list of txids which will be found in the
+ * given block.
+ */
+BOOST_AUTO_TEST_CASE(merkleblock_construct_from_txids_found)
+{
+ CBlock block = getBlock13b8a();
+
+ std::set<uint256> txids;
+
+ // Last txn in block.
+ uint256 txhash1 = uint256S("0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20");
+
+ // Second txn in block.
+ uint256 txhash2 = uint256S("0xf9fc751cb7dc372406a9f8d738d5e6f8f63bab71986a39cf36ee70ee17036d07");
+
+ txids.insert(txhash1);
+ txids.insert(txhash2);
+
+ CMerkleBlock merkleBlock(block, txids);
+
+ BOOST_CHECK_EQUAL(merkleBlock.header.GetHash().GetHex(), block.GetHash().GetHex());
+
+ // vMatchedTxn is only used when bloom filter is specified.
+ BOOST_CHECK_EQUAL(merkleBlock.vMatchedTxn.size(), 0);
+
+ std::vector<uint256> vMatched;
+ std::vector<unsigned int> vIndex;
+
+ BOOST_CHECK_EQUAL(merkleBlock.txn.ExtractMatches(vMatched, vIndex).GetHex(), block.hashMerkleRoot.GetHex());
+ BOOST_CHECK_EQUAL(vMatched.size(), 2);
+
+ // Ordered by occurrence in depth-first tree traversal.
+ BOOST_CHECK_EQUAL(vMatched[0].ToString(), txhash2.ToString());
+ BOOST_CHECK_EQUAL(vIndex[0], 1);
+
+ BOOST_CHECK_EQUAL(vMatched[1].ToString(), txhash1.ToString());
+ BOOST_CHECK_EQUAL(vIndex[1], 8);
+}
+
+
+/**
+ * Create a CMerkleBlock using a list of txids which will not be found in the
+ * given block.
+ */
+BOOST_AUTO_TEST_CASE(merkleblock_construct_from_txids_not_found)
+{
+ CBlock block = getBlock13b8a();
+
+ std::set<uint256> txids2;
+ txids2.insert(uint256S("0xc0ffee00003bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20"));
+ CMerkleBlock merkleBlock(block, txids2);
+
+ BOOST_CHECK_EQUAL(merkleBlock.header.GetHash().GetHex(), block.GetHash().GetHex());
+ BOOST_CHECK_EQUAL(merkleBlock.vMatchedTxn.size(), 0);
+
+ std::vector<uint256> vMatched;
+ std::vector<unsigned int> vIndex;
+
+ BOOST_CHECK_EQUAL(merkleBlock.txn.ExtractMatches(vMatched, vIndex).GetHex(), block.hashMerkleRoot.GetHex());
+ BOOST_CHECK_EQUAL(vMatched.size(), 0);
+ BOOST_CHECK_EQUAL(vIndex.size(), 0);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 2f74f57d00..41e0626eb9 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -6,9 +6,11 @@
#include "coins.h"
#include "consensus/consensus.h"
#include "consensus/merkle.h"
+#include "consensus/tx_verify.h"
#include "consensus/validation.h"
#include "validation.h"
#include "miner.h"
+#include "policy/policy.h"
#include "pubkey.h"
#include "script/standard.h"
#include "txmempool.h"
@@ -24,6 +26,16 @@
BOOST_FIXTURE_TEST_SUITE(miner_tests, TestingSetup)
+static CFeeRate blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
+
+static BlockAssembler AssemblerForTest(const CChainParams& params) {
+ BlockAssembler::Options options;
+
+ options.nBlockMaxWeight = MAX_BLOCK_WEIGHT;
+ options.blockMinFeeRate = blockMinFeeRate;
+ return BlockAssembler(params, options);
+}
+
static
struct {
unsigned char extranonce;
@@ -76,7 +88,6 @@ bool TestSequenceLocks(const CTransaction &tx, int flags)
// Test suite for ancestor feerate transaction selection.
// Implemented as an additional function, rather than a separate test case,
// to allow reusing the blockchain created in CreateNewBlock_validity.
-// Note that this test assumes blockprioritysize is 0.
void TestPackageSelection(const CChainParams& chainparams, CScript scriptPubKey, std::vector<CTransactionRef>& txFirst)
{
// Test the ancestor feerate transaction selection.
@@ -107,12 +118,12 @@ void TestPackageSelection(const CChainParams& chainparams, CScript scriptPubKey,
uint256 hashHighFeeTx = tx.GetHash();
mempool.addUnchecked(hashHighFeeTx, entry.Fee(50000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
- std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey);
+ std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashParentTx);
BOOST_CHECK(pblocktemplate->block.vtx[2]->GetHash() == hashHighFeeTx);
BOOST_CHECK(pblocktemplate->block.vtx[3]->GetHash() == hashMediumFeeTx);
- // Test that a package below the min relay fee doesn't get included
+ // Test that a package below the block min tx fee doesn't get included
tx.vin[0].prevout.hash = hashHighFeeTx;
tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 0 fee
uint256 hashFreeTx = tx.GetHash();
@@ -120,14 +131,14 @@ void TestPackageSelection(const CChainParams& chainparams, CScript scriptPubKey,
size_t freeTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
// Calculate a fee on child transaction that will put the package just
- // below the min relay fee (assuming 1 child tx of the same size).
- CAmount feeToUse = minRelayTxFee.GetFee(2*freeTxSize) - 1;
+ // below the block min tx fee (assuming 1 child tx of the same size).
+ CAmount feeToUse = blockMinFeeRate.GetFee(2*freeTxSize) - 1;
tx.vin[0].prevout.hash = hashFreeTx;
tx.vout[0].nValue = 5000000000LL - 1000 - 50000 - feeToUse;
uint256 hashLowFeeTx = tx.GetHash();
mempool.addUnchecked(hashLowFeeTx, entry.Fee(feeToUse).FromTx(tx));
- pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey);
+ pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
// Verify that the free tx and the low fee tx didn't get selected
for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) {
BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashFreeTx);
@@ -141,7 +152,7 @@ void TestPackageSelection(const CChainParams& chainparams, CScript scriptPubKey,
tx.vout[0].nValue -= 2; // Now we should be just over the min relay fee
hashLowFeeTx = tx.GetHash();
mempool.addUnchecked(hashLowFeeTx, entry.Fee(feeToUse+2).FromTx(tx));
- pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey);
+ pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
BOOST_CHECK(pblocktemplate->block.vtx[4]->GetHash() == hashFreeTx);
BOOST_CHECK(pblocktemplate->block.vtx[5]->GetHash() == hashLowFeeTx);
@@ -158,11 +169,11 @@ void TestPackageSelection(const CChainParams& chainparams, CScript scriptPubKey,
// This tx can't be mined by itself
tx.vin[0].prevout.hash = hashFreeTx2;
tx.vout.resize(1);
- feeToUse = minRelayTxFee.GetFee(freeTxSize);
+ feeToUse = blockMinFeeRate.GetFee(freeTxSize);
tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse;
uint256 hashLowFeeTx2 = tx.GetHash();
mempool.addUnchecked(hashLowFeeTx2, entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx));
- pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey);
+ pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
// Verify that this tx isn't selected.
for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) {
@@ -175,7 +186,7 @@ void TestPackageSelection(const CChainParams& chainparams, CScript scriptPubKey,
tx.vin[0].prevout.n = 1;
tx.vout[0].nValue = 100000000 - 10000; // 10k satoshi fee
mempool.addUnchecked(tx.GetHash(), entry.Fee(10000).FromTx(tx));
- pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey);
+ pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
BOOST_CHECK(pblocktemplate->block.vtx[8]->GetHash() == hashLowFeeTx2);
}
@@ -183,7 +194,8 @@ void TestPackageSelection(const CChainParams& chainparams, CScript scriptPubKey,
BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
{
// Note that by default, these tests run with size accounting enabled.
- const CChainParams& chainparams = Params(CBaseChainParams::MAIN);
+ const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);
+ const CChainParams& chainparams = *chainParams;
CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
std::unique_ptr<CBlockTemplate> pblocktemplate;
CMutableTransaction tx,tx2;
@@ -191,14 +203,13 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
uint256 hash;
TestMemPoolEntryHelper entry;
entry.nFee = 11;
- entry.dPriority = 111.0;
entry.nHeight = 11;
LOCK(cs_main);
fCheckpointsEnabled = false;
// Simple block creation, nothing special yet:
- BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey));
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
// We can't make transactions until we have inputs
// Therefore, load 100 blocks :)
@@ -224,12 +235,12 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
pblock->nNonce = blockinfo[i].nonce;
std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(*pblock);
- BOOST_CHECK(ProcessNewBlock(chainparams, shared_pblock, true, NULL));
+ BOOST_CHECK(ProcessNewBlock(chainparams, shared_pblock, true, nullptr));
pblock->hashPrevBlock = pblock->GetHash();
}
// Just to make sure we can still make simple blocks
- BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey));
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
const CAmount BLOCKSUBSIDY = 50*COIN;
const CAmount LOWFEE = CENT;
@@ -248,12 +259,12 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
{
tx.vout[0].nValue -= LOWFEE;
hash = tx.GetHash();
- bool spendsCoinbase = (i == 0) ? true : false; // only first tx spends coinbase
+ bool spendsCoinbase = i == 0; // only first tx spends coinbase
// If we don't set the # of sig ops in the CTxMemPoolEntry, template creation fails
mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
tx.vin[0].prevout.hash = hash;
}
- BOOST_CHECK_THROW(BlockAssembler(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error);
+ BOOST_CHECK_THROW(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error);
mempool.clear();
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
@@ -262,12 +273,12 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
{
tx.vout[0].nValue -= LOWFEE;
hash = tx.GetHash();
- bool spendsCoinbase = (i == 0) ? true : false; // only first tx spends coinbase
+ bool spendsCoinbase = i == 0; // only first tx spends coinbase
// If we do set the # of sig ops in the CTxMemPoolEntry, template creation passes
mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).SigOpsCost(80).FromTx(tx));
tx.vin[0].prevout.hash = hash;
}
- BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey));
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
mempool.clear();
// block size > limit
@@ -283,20 +294,20 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
{
tx.vout[0].nValue -= LOWFEE;
hash = tx.GetHash();
- bool spendsCoinbase = (i == 0) ? true : false; // only first tx spends coinbase
+ bool spendsCoinbase = i == 0; // only first tx spends coinbase
mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
tx.vin[0].prevout.hash = hash;
}
- BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey));
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
mempool.clear();
// orphan in mempool, template creation fails
hash = tx.GetHash();
mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx));
- BOOST_CHECK_THROW(BlockAssembler(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error);
+ BOOST_CHECK_THROW(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error);
mempool.clear();
- // child with higher priority than parent
+ // child with higher feerate than parent
tx.vin[0].scriptSig = CScript() << OP_1;
tx.vin[0].prevout.hash = txFirst[1]->GetHash();
tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE;
@@ -310,7 +321,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vout[0].nValue = tx.vout[0].nValue+BLOCKSUBSIDY-HIGHERFEE; //First txn output + fresh coinbase - new txn fee
hash = tx.GetHash();
mempool.addUnchecked(hash, entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
- BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey));
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
mempool.clear();
// coinbase in mempool, template creation fails
@@ -321,7 +332,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
hash = tx.GetHash();
// give it a fee so it'll get mined
mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
- BOOST_CHECK_THROW(BlockAssembler(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error);
+ BOOST_CHECK_THROW(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error);
mempool.clear();
// invalid (pre-p2sh) txn in mempool, template creation fails
@@ -338,7 +349,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vout[0].nValue -= LOWFEE;
hash = tx.GetHash();
mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
- BOOST_CHECK_THROW(BlockAssembler(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error);
+ BOOST_CHECK_THROW(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error);
mempool.clear();
// double spend txn pair in mempool, template creation fails
@@ -351,7 +362,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vout[0].scriptPubKey = CScript() << OP_2;
hash = tx.GetHash();
mempool.addUnchecked(hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
- BOOST_CHECK_THROW(BlockAssembler(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error);
+ BOOST_CHECK_THROW(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error);
mempool.clear();
// subsidy changing
@@ -360,26 +371,26 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
while (chainActive.Tip()->nHeight < 209999) {
CBlockIndex* prev = chainActive.Tip();
CBlockIndex* next = new CBlockIndex();
- next->phashBlock = new uint256(GetRandHash());
+ next->phashBlock = new uint256(InsecureRand256());
pcoinsTip->SetBestBlock(next->GetBlockHash());
next->pprev = prev;
next->nHeight = prev->nHeight + 1;
next->BuildSkip();
chainActive.SetTip(next);
}
- BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey));
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
// Extend to a 210000-long block chain.
while (chainActive.Tip()->nHeight < 210000) {
CBlockIndex* prev = chainActive.Tip();
CBlockIndex* next = new CBlockIndex();
- next->phashBlock = new uint256(GetRandHash());
+ next->phashBlock = new uint256(InsecureRand256());
pcoinsTip->SetBestBlock(next->GetBlockHash());
next->pprev = prev;
next->nHeight = prev->nHeight + 1;
next->BuildSkip();
chainActive.SetTip(next);
}
- BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey));
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
// Delete the dummy blocks again.
while (chainActive.Tip()->nHeight > nHeight) {
CBlockIndex* del = chainActive.Tip();
@@ -465,7 +476,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | 1;
BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks fail
- BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey));
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
// None of the of the absolute height/time locked tx should have made
// it into the template because we still check IsFinalTx in CreateNewBlock,
@@ -478,7 +489,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
chainActive.Tip()->nHeight++;
SetMockTime(chainActive.Tip()->GetMedianTimePast() + 1);
- BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey));
+ BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5);
chainActive.Tip()->nHeight--;
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
index dd5678ea6e..de7f3b48f5 100644
--- a/src/test/multisig_tests.cpp
+++ b/src/test/multisig_tests.cpp
@@ -14,11 +14,8 @@
#include "test/test_bitcoin.h"
-#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
-typedef std::vector<unsigned char> valtype;
-
BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup)
CScript
@@ -28,7 +25,7 @@ sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transac
CScript result;
result << OP_0; // CHECKMULTISIG bug workaround
- BOOST_FOREACH(const CKey &key, keys)
+ for (const CKey &key : keys)
{
std::vector<unsigned char> vchSig;
BOOST_CHECK(key.Sign(hash, vchSig));
@@ -80,20 +77,20 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
keys.assign(1,key[0]);
keys.push_back(key[1]);
s = sign_multisig(a_and_b, keys, txTo[0], 0);
- BOOST_CHECK(VerifyScript(s, a_and_b, NULL, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err));
+ BOOST_CHECK(VerifyScript(s, a_and_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
for (int i = 0; i < 4; i++)
{
keys.assign(1,key[i]);
s = sign_multisig(a_and_b, keys, txTo[0], 0);
- BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, NULL, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err), strprintf("a&b 1: %d", i));
+ BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err), strprintf("a&b 1: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
keys.assign(1,key[1]);
keys.push_back(key[i]);
s = sign_multisig(a_and_b, keys, txTo[0], 0);
- BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, NULL, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err), strprintf("a&b 2: %d", i));
+ BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err), strprintf("a&b 2: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
}
@@ -104,18 +101,18 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
s = sign_multisig(a_or_b, keys, txTo[1], 0);
if (i == 0 || i == 1)
{
- BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, NULL, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err), strprintf("a|b: %d", i));
+ BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err), strprintf("a|b: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
}
else
{
- BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, NULL, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err), strprintf("a|b: %d", i));
+ BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err), strprintf("a|b: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
}
}
s.clear();
s << OP_0 << OP_1;
- BOOST_CHECK(!VerifyScript(s, a_or_b, NULL, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err));
+ BOOST_CHECK(!VerifyScript(s, a_or_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err));
@@ -127,12 +124,12 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
s = sign_multisig(escrow, keys, txTo[2], 0);
if (i < j && i < 3 && j < 3)
{
- BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, NULL, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), &err), strprintf("escrow 1: %d %d", i, j));
+ BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, nullptr, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), &err), strprintf("escrow 1: %d %d", i, j));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
}
else
{
- BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, NULL, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), &err), strprintf("escrow 2: %d %d", i, j));
+ BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, nullptr, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), &err), strprintf("escrow 2: %d %d", i, j));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
}
}
@@ -174,95 +171,6 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard)
BOOST_CHECK(!::IsStandard(malformed[i], whichType));
}
-BOOST_AUTO_TEST_CASE(multisig_Solver1)
-{
- // Tests Solver() that returns lists of keys that are
- // required to satisfy a ScriptPubKey
- //
- // Also tests IsMine() and ExtractDestination()
- //
- // Note: ExtractDestination for the multisignature transactions
- // always returns false for this release, even if you have
- // one key that would satisfy an (a|b) or 2-of-3 keys needed
- // to spend an escrow transaction.
- //
- CBasicKeyStore keystore, emptykeystore, partialkeystore;
- CKey key[3];
- CTxDestination keyaddr[3];
- for (int i = 0; i < 3; i++)
- {
- key[i].MakeNewKey(true);
- keystore.AddKey(key[i]);
- keyaddr[i] = key[i].GetPubKey().GetID();
- }
- partialkeystore.AddKey(key[0]);
-
- {
- std::vector<valtype> solutions;
- txnouttype whichType;
- CScript s;
- s << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG;
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK(solutions.size() == 1);
- CTxDestination addr;
- BOOST_CHECK(ExtractDestination(s, addr));
- BOOST_CHECK(addr == keyaddr[0]);
- BOOST_CHECK(IsMine(keystore, s));
- BOOST_CHECK(!IsMine(emptykeystore, s));
- }
- {
- std::vector<valtype> solutions;
- txnouttype whichType;
- CScript s;
- s << OP_DUP << OP_HASH160 << ToByteVector(key[0].GetPubKey().GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK(solutions.size() == 1);
- CTxDestination addr;
- BOOST_CHECK(ExtractDestination(s, addr));
- BOOST_CHECK(addr == keyaddr[0]);
- BOOST_CHECK(IsMine(keystore, s));
- BOOST_CHECK(!IsMine(emptykeystore, s));
- }
- {
- std::vector<valtype> solutions;
- txnouttype whichType;
- CScript s;
- s << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK_EQUAL(solutions.size(), 4U);
- CTxDestination addr;
- BOOST_CHECK(!ExtractDestination(s, addr));
- BOOST_CHECK(IsMine(keystore, s));
- BOOST_CHECK(!IsMine(emptykeystore, s));
- BOOST_CHECK(!IsMine(partialkeystore, s));
- }
- {
- std::vector<valtype> solutions;
- txnouttype whichType;
- CScript s;
- s << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK_EQUAL(solutions.size(), 4U);
- std::vector<CTxDestination> addrs;
- int nRequired;
- BOOST_CHECK(ExtractDestinations(s, whichType, addrs, nRequired));
- BOOST_CHECK(addrs[0] == keyaddr[0]);
- BOOST_CHECK(addrs[1] == keyaddr[1]);
- BOOST_CHECK(nRequired == 1);
- BOOST_CHECK(IsMine(keystore, s));
- BOOST_CHECK(!IsMine(emptykeystore, s));
- BOOST_CHECK(!IsMine(partialkeystore, s));
- }
- {
- std::vector<valtype> solutions;
- txnouttype whichType;
- CScript s;
- s << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK(solutions.size() == 5);
- }
-}
-
BOOST_AUTO_TEST_CASE(multisig_Sign)
{
// Test SignSignature() (and therefore the version of Solver() that signs transactions)
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index 0bd7869f32..31b05d868b 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -11,6 +11,7 @@
#include "net.h"
#include "netbase.h"
#include "chainparams.h"
+#include "util.h"
class CAddrManSerializationMock : public CAddrMan
{
@@ -28,7 +29,7 @@ public:
class CAddrManUncorrupted : public CAddrManSerializationMock
{
public:
- void Serialize(CDataStream& s) const
+ void Serialize(CDataStream& s) const override
{
CAddrMan::Serialize(s);
}
@@ -37,7 +38,7 @@ public:
class CAddrManCorrupted : public CAddrManSerializationMock
{
public:
- void Serialize(CDataStream& s) const
+ void Serialize(CDataStream& s) const override
{
// Produces corrupt output that claims addrman has 20 addrs when it only has one addr.
unsigned char nVersion = 1;
@@ -72,6 +73,18 @@ CDataStream AddrmanToStream(CAddrManSerializationMock& _addrman)
BOOST_FIXTURE_TEST_SUITE(net_tests, BasicTestingSetup)
+BOOST_AUTO_TEST_CASE(cnode_listen_port)
+{
+ // test default
+ unsigned short port = GetListenPort();
+ BOOST_CHECK(port == Params().GetDefaultPort());
+ // test set port
+ unsigned short altPort = 12345;
+ gArgs.SoftSetArg("-port", std::to_string(altPort));
+ port = GetListenPort();
+ BOOST_CHECK(port == altPort);
+}
+
BOOST_AUTO_TEST_CASE(caddrdb_read)
{
CAddrManUncorrupted addrmanUncorrupted;
@@ -162,12 +175,12 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
bool fInboundIn = false;
// Test that fFeeler is false by default.
- CNode* pnode1 = new CNode(id++, NODE_NETWORK, height, hSocket, addr, 0, 0, pszDest, fInboundIn);
+ std::unique_ptr<CNode> pnode1(new CNode(id++, NODE_NETWORK, height, hSocket, addr, 0, 0, CAddress(), pszDest, fInboundIn));
BOOST_CHECK(pnode1->fInbound == false);
BOOST_CHECK(pnode1->fFeeler == false);
fInboundIn = true;
- CNode* pnode2 = new CNode(id++, NODE_NETWORK, height, hSocket, addr, 1, 1, pszDest, fInboundIn);
+ std::unique_ptr<CNode> pnode2(new CNode(id++, NODE_NETWORK, height, hSocket, addr, 1, 1, CAddress(), pszDest, fInboundIn));
BOOST_CHECK(pnode2->fInbound == true);
BOOST_CHECK(pnode2->fFeeler == false);
}
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index 1afef5b1ce..1baf7643e5 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -4,10 +4,10 @@
#include "netbase.h"
#include "test/test_bitcoin.h"
+#include "utilstrencodings.h"
#include <string>
-#include <boost/assign/list_of.hpp>
#include <boost/test/unit_test.hpp>
BOOST_FIXTURE_TEST_SUITE(netbase_tests, BasicTestingSetup)
@@ -26,6 +26,13 @@ static CSubNet ResolveSubNet(const char* subnet)
return ret;
}
+static CNetAddr CreateInternal(const char* host)
+{
+ CNetAddr addr;
+ addr.SetInternal(host);
+ return addr;
+}
+
BOOST_AUTO_TEST_CASE(netbase_networks)
{
BOOST_CHECK(ResolveIP("127.0.0.1").GetNetwork() == NET_UNROUTABLE);
@@ -33,6 +40,7 @@ BOOST_AUTO_TEST_CASE(netbase_networks)
BOOST_CHECK(ResolveIP("8.8.8.8").GetNetwork() == NET_IPV4);
BOOST_CHECK(ResolveIP("2001::8888").GetNetwork() == NET_IPV6);
BOOST_CHECK(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetNetwork() == NET_TOR);
+ BOOST_CHECK(CreateInternal("foo.com").GetNetwork() == NET_INTERNAL);
}
@@ -59,6 +67,8 @@ BOOST_AUTO_TEST_CASE(netbase_properties)
BOOST_CHECK(ResolveIP("8.8.8.8").IsRoutable());
BOOST_CHECK(ResolveIP("2001::1").IsRoutable());
BOOST_CHECK(ResolveIP("127.0.0.1").IsValid());
+ BOOST_CHECK(CreateInternal("FD6B:88C0:8724:edb1:8e4:3588:e546:35ca").IsInternal());
+ BOOST_CHECK(CreateInternal("bar.com").IsInternal());
}
@@ -104,6 +114,11 @@ BOOST_AUTO_TEST_CASE(netbase_lookupnumeric)
BOOST_CHECK(TestParse("[::]:8333", "[::]:8333"));
BOOST_CHECK(TestParse("[127.0.0.1]", "127.0.0.1:65535"));
BOOST_CHECK(TestParse(":::", "[::]:0"));
+
+ // verify that an internal address fails to resolve
+ BOOST_CHECK(TestParse("[fd6b:88c0:8724:1:2:3:4:5]", "[::]:0"));
+ // and that a one-off resolves correctly
+ BOOST_CHECK(TestParse("[fd6c:88c0:8724:1:2:3:4:5]", "[fd6c:88c0:8724:1:2:3:4:5]:65535"));
}
BOOST_AUTO_TEST_CASE(onioncat_test)
@@ -269,19 +284,22 @@ BOOST_AUTO_TEST_CASE(subnet_test)
BOOST_AUTO_TEST_CASE(netbase_getgroup)
{
- BOOST_CHECK(ResolveIP("127.0.0.1").GetGroup() == boost::assign::list_of(0)); // Local -> !Routable()
- BOOST_CHECK(ResolveIP("257.0.0.1").GetGroup() == boost::assign::list_of(0)); // !Valid -> !Routable()
- BOOST_CHECK(ResolveIP("10.0.0.1").GetGroup() == boost::assign::list_of(0)); // RFC1918 -> !Routable()
- BOOST_CHECK(ResolveIP("169.254.1.1").GetGroup() == boost::assign::list_of(0)); // RFC3927 -> !Routable()
- BOOST_CHECK(ResolveIP("1.2.3.4").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // IPv4
- BOOST_CHECK(ResolveIP("::FFFF:0:102:304").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // RFC6145
- BOOST_CHECK(ResolveIP("64:FF9B::102:304").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // RFC6052
- BOOST_CHECK(ResolveIP("2002:102:304:9999:9999:9999:9999:9999").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // RFC3964
- BOOST_CHECK(ResolveIP("2001:0:9999:9999:9999:9999:FEFD:FCFB").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // RFC4380
- BOOST_CHECK(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetGroup() == boost::assign::list_of((unsigned char)NET_TOR)(239)); // Tor
- BOOST_CHECK(ResolveIP("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(ResolveIP("2001:2001:9999:9999:9999:9999:9999:9999").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV6)(32)(1)(32)(1)); //IPv6
+ BOOST_CHECK(ResolveIP("127.0.0.1").GetGroup() == std::vector<unsigned char>({0})); // Local -> !Routable()
+ BOOST_CHECK(ResolveIP("257.0.0.1").GetGroup() == std::vector<unsigned char>({0})); // !Valid -> !Routable()
+ BOOST_CHECK(ResolveIP("10.0.0.1").GetGroup() == std::vector<unsigned char>({0})); // RFC1918 -> !Routable()
+ BOOST_CHECK(ResolveIP("169.254.1.1").GetGroup() == std::vector<unsigned char>({0})); // RFC3927 -> !Routable()
+ BOOST_CHECK(ResolveIP("1.2.3.4").GetGroup() == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // IPv4
+ BOOST_CHECK(ResolveIP("::FFFF:0:102:304").GetGroup() == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC6145
+ BOOST_CHECK(ResolveIP("64:FF9B::102:304").GetGroup() == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC6052
+ BOOST_CHECK(ResolveIP("2002:102:304:9999:9999:9999:9999:9999").GetGroup() == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC3964
+ BOOST_CHECK(ResolveIP("2001:0:9999:9999:9999:9999:FEFD:FCFB").GetGroup() == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC4380
+ BOOST_CHECK(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetGroup() == std::vector<unsigned char>({(unsigned char)NET_TOR, 239})); // Tor
+ BOOST_CHECK(ResolveIP("2001:470:abcd:9999:9999:9999:9999:9999").GetGroup() == std::vector<unsigned char>({(unsigned char)NET_IPV6, 32, 1, 4, 112, 175})); //he.net
+ BOOST_CHECK(ResolveIP("2001:2001:9999:9999:9999:9999:9999:9999").GetGroup() == std::vector<unsigned char>({(unsigned char)NET_IPV6, 32, 1, 32, 1})); //IPv6
+ // baz.net sha256 hash: 12929400eb4607c4ac075f087167e75286b179c693eb059a01774b864e8fe505
+ std::vector<unsigned char> internal_group = {NET_INTERNAL, 0x12, 0x92, 0x94, 0x00, 0xeb, 0x46, 0x07, 0xc4, 0xac, 0x07};
+ BOOST_CHECK(CreateInternal("baz.net").GetGroup() == internal_group);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp
index a1cb32019a..c1d216d094 100644
--- a/src/test/pmt_tests.cpp
+++ b/src/test/pmt_tests.cpp
@@ -10,11 +10,9 @@
#include "arith_uint256.h"
#include "version.h"
#include "test/test_bitcoin.h"
-#include "test/test_random.h"
#include <vector>
-#include <boost/assign/list_of.hpp>
#include <boost/test/unit_test.hpp>
class CPartialMerkleTreeTester : public CPartialMerkleTree
@@ -22,8 +20,8 @@ class CPartialMerkleTreeTester : public CPartialMerkleTree
public:
// flip one bit in one of the hashes - this should break the authentication
void Damage() {
- unsigned int n = insecure_rand() % vHash.size();
- int bit = insecure_rand() % 256;
+ unsigned int n = InsecureRandRange(vHash.size());
+ int bit = InsecureRandBits(8);
*(vHash[n].begin() + (bit>>3)) ^= 1<<(bit&7);
}
};
@@ -32,7 +30,7 @@ BOOST_FIXTURE_TEST_SUITE(pmt_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(pmt_test1)
{
- seed_insecure_rand(false);
+ SeedInsecureRand(false);
static const unsigned int nTxCounts[] = {1, 4, 7, 17, 56, 100, 127, 256, 312, 513, 1000, 4095};
for (int i = 0; i < 12; i++) {
@@ -63,7 +61,7 @@ BOOST_AUTO_TEST_CASE(pmt_test1)
std::vector<bool> vMatch(nTx, false);
std::vector<uint256> vMatchTxid1;
for (unsigned int j=0; j<nTx; j++) {
- bool fInclude = (insecure_rand() & ((1 << (att/2)) - 1)) == 0;
+ bool fInclude = InsecureRandBits(att / 2) == 0;
vMatch[j] = fInclude;
if (fInclude)
vMatchTxid1.push_back(vTxid[j]);
@@ -110,14 +108,15 @@ BOOST_AUTO_TEST_CASE(pmt_test1)
BOOST_AUTO_TEST_CASE(pmt_malleability)
{
- std::vector<uint256> vTxid = boost::assign::list_of
- (ArithToUint256(1))(ArithToUint256(2))
- (ArithToUint256(3))(ArithToUint256(4))
- (ArithToUint256(5))(ArithToUint256(6))
- (ArithToUint256(7))(ArithToUint256(8))
- (ArithToUint256(9))(ArithToUint256(10))
- (ArithToUint256(9))(ArithToUint256(10));
- std::vector<bool> vMatch = boost::assign::list_of(false)(false)(false)(false)(false)(false)(false)(false)(false)(true)(true)(false);
+ std::vector<uint256> vTxid = {
+ ArithToUint256(1), ArithToUint256(2),
+ ArithToUint256(3), ArithToUint256(4),
+ ArithToUint256(5), ArithToUint256(6),
+ ArithToUint256(7), ArithToUint256(8),
+ ArithToUint256(9), ArithToUint256(10),
+ ArithToUint256(9), ArithToUint256(10),
+ };
+ std::vector<bool> vMatch = {false, false, false, false, false, false, false, false, false, true, true, false};
CPartialMerkleTree tree(vTxid, vMatch);
std::vector<unsigned int> vIndex;
diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp
index 0c060801bc..fd8f7191f4 100644
--- a/src/test/policyestimator_tests.cpp
+++ b/src/test/policyestimator_tests.cpp
@@ -16,7 +16,8 @@ BOOST_FIXTURE_TEST_SUITE(policyestimator_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
{
- CTxMemPool mpool(CFeeRate(1000));
+ CBlockPolicyEstimator feeEst;
+ CTxMemPool mpool(&feeEst);
TestMemPoolEntryHelper entry;
CAmount basefee(2000);
CAmount deltaFee(100);
@@ -49,14 +50,14 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
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
+ // At a decay .9952 and 4 fee transactions per block
+ // This makes the tx count about 2.5 per bucket, well above the 0.1 threshold
while (blocknum < 200) {
for (int j = 0; j < 10; j++) { // For each fee
for (int k = 0; k < 4; k++) { // add 4 fee txs
tx.vin[0].prevout.n = 10000*blocknum+100*j+k; // make transaction unique
uint256 hash = tx.GetHash();
- mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Priority(0).Height(blocknum).FromTx(tx, &mpool));
+ mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx));
txHashes[j].push_back(hash);
}
}
@@ -74,20 +75,14 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
}
mpool.removeForBlock(block, ++blocknum);
block.clear();
- if (blocknum == 30) {
- // At this point we should need to combine 5 buckets to get enough data points
- // So estimateFee(1,2,3) should fail and estimateFee(4) should return somewhere around
- // 8*baserate. estimateFee(4) %'s are 100,100,100,100,90 = average 98%
- BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0));
- BOOST_CHECK(mpool.estimateFee(2) == CFeeRate(0));
- BOOST_CHECK(mpool.estimateFee(3) == CFeeRate(0));
- BOOST_CHECK(mpool.estimateFee(4).GetFeePerK() < 8*baseRate.GetFeePerK() + deltaFee);
- BOOST_CHECK(mpool.estimateFee(4).GetFeePerK() > 8*baseRate.GetFeePerK() - deltaFee);
- int answerFound;
- BOOST_CHECK(mpool.estimateSmartFee(1, &answerFound) == mpool.estimateFee(4) && answerFound == 4);
- BOOST_CHECK(mpool.estimateSmartFee(3, &answerFound) == mpool.estimateFee(4) && answerFound == 4);
- BOOST_CHECK(mpool.estimateSmartFee(4, &answerFound) == mpool.estimateFee(4) && answerFound == 4);
- BOOST_CHECK(mpool.estimateSmartFee(8, &answerFound) == mpool.estimateFee(8) && answerFound == 8);
+ // Check after just a few txs that combining buckets works as expected
+ if (blocknum == 3) {
+ // At this point we should need to combine 3 buckets to get enough data points
+ // So estimateFee(1) should fail and estimateFee(2) should return somewhere around
+ // 9*baserate. estimateFee(2) %'s are 100,100,90 = average 97%
+ BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0));
+ BOOST_CHECK(feeEst.estimateFee(2).GetFeePerK() < 9*baseRate.GetFeePerK() + deltaFee);
+ BOOST_CHECK(feeEst.estimateFee(2).GetFeePerK() > 9*baseRate.GetFeePerK() - deltaFee);
}
}
@@ -99,18 +94,19 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
// Second highest feerate has 100% chance of being included by 2 blocks,
// so estimateFee(2) should return 9*baseRate etc...
for (int i = 1; i < 10;i++) {
- origFeeEst.push_back(mpool.estimateFee(i).GetFeePerK());
+ origFeeEst.push_back(feeEst.estimateFee(i).GetFeePerK());
if (i > 2) { // Fee estimates should be monotonically decreasing
BOOST_CHECK(origFeeEst[i-1] <= origFeeEst[i-2]);
}
int mult = 11-i;
- if (i > 1) {
+ if (i % 2 == 0) { //At scale 2, test logic is only correct for even targets
BOOST_CHECK(origFeeEst[i-1] < mult*baseRate.GetFeePerK() + deltaFee);
BOOST_CHECK(origFeeEst[i-1] > mult*baseRate.GetFeePerK() - deltaFee);
}
- else {
- BOOST_CHECK(origFeeEst[i-1] == CFeeRate(0).GetFeePerK());
- }
+ }
+ // Fill out rest of the original estimates
+ for (int i = 10; i <= 48; i++) {
+ origFeeEst.push_back(feeEst.estimateFee(i).GetFeePerK());
}
// Mine 50 more blocks with no transactions happening, estimates shouldn't change
@@ -118,10 +114,10 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
while (blocknum < 250)
mpool.removeForBlock(block, ++blocknum);
- BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0));
+ BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0));
for (int i = 2; 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(feeEst.estimateFee(i).GetFeePerK() < origFeeEst[i-1] + deltaFee);
+ BOOST_CHECK(feeEst.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
}
@@ -132,17 +128,15 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
for (int k = 0; k < 4; k++) { // add 4 fee txs
tx.vin[0].prevout.n = 10000*blocknum+100*j+k;
uint256 hash = tx.GetHash();
- mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Priority(0).Height(blocknum).FromTx(tx, &mpool));
+ mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx));
txHashes[j].push_back(hash);
}
}
mpool.removeForBlock(block, ++blocknum);
}
- int answerFound;
for (int i = 1; i < 10;i++) {
- BOOST_CHECK(mpool.estimateFee(i) == CFeeRate(0) || mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
- BOOST_CHECK(mpool.estimateSmartFee(i, &answerFound).GetFeePerK() > origFeeEst[answerFound-1] - deltaFee);
+ BOOST_CHECK(feeEst.estimateFee(i) == CFeeRate(0) || feeEst.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
}
// Mine all those transactions
@@ -155,21 +149,21 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
txHashes[j].pop_back();
}
}
- mpool.removeForBlock(block, 265);
+ mpool.removeForBlock(block, 266);
block.clear();
- BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0));
+ BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0));
for (int i = 2; i < 10;i++) {
- BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
+ BOOST_CHECK(feeEst.estimateFee(i) == CFeeRate(0) || feeEst.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
}
- // Mine 200 more blocks where everything is mined every block
+ // Mine 400 more blocks where everything is mined every block
// Estimates should be below original estimates
- while (blocknum < 465) {
+ while (blocknum < 665) {
for (int j = 0; j < 10; j++) { // For each fee multiple
for (int k = 0; k < 4; k++) { // add 4 fee txs
tx.vin[0].prevout.n = 10000*blocknum+100*j+k;
uint256 hash = tx.GetHash();
- mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Priority(0).Height(blocknum).FromTx(tx, &mpool));
+ mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx));
CTransactionRef ptx = mpool.get(hash);
if (ptx)
block.push_back(ptx);
@@ -179,21 +173,9 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
mpool.removeForBlock(block, ++blocknum);
block.clear();
}
- BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0));
- for (int i = 2; i < 10; i++) {
- BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] - deltaFee);
- }
-
- // Test that if the mempool is limited, estimateSmartFee won't return a value below the mempool min fee
- // and that estimateSmartPriority returns essentially an infinite value
- mpool.addUnchecked(tx.GetHash(), entry.Fee(feeV[5]).Time(GetTime()).Priority(0).Height(blocknum).FromTx(tx, &mpool));
- // evict that transaction which should set a mempool min fee of minRelayTxFee + feeV[5]
- mpool.TrimToSize(1);
- BOOST_CHECK(mpool.GetMinFee(1).GetFeePerK() > feeV[5]);
- for (int i = 1; i < 10; i++) {
- BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >= mpool.estimateFee(i).GetFeePerK());
- BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >= mpool.GetMinFee(1).GetFeePerK());
- BOOST_CHECK(mpool.estimateSmartPriority(i) == INF_PRIORITY);
+ BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0));
+ for (int i = 2; i < 9; i++) { // At 9, the original estimate was already at the bottom (b/c scale = 2)
+ BOOST_CHECK(feeEst.estimateFee(i).GetFeePerK() < origFeeEst[i-1] - deltaFee);
}
}
diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp
index 4ca6f1caf0..b13f2625aa 100644
--- a/src/test/pow_tests.cpp
+++ b/src/test/pow_tests.cpp
@@ -16,79 +16,69 @@ BOOST_FIXTURE_TEST_SUITE(pow_tests, BasicTestingSetup)
/* Test calculation of next difficulty target with no constraints applying */
BOOST_AUTO_TEST_CASE(get_next_work)
{
- SelectParams(CBaseChainParams::MAIN);
- const Consensus::Params& params = Params().GetConsensus();
-
+ const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);
int64_t nLastRetargetTime = 1261130161; // Block #30240
CBlockIndex pindexLast;
pindexLast.nHeight = 32255;
pindexLast.nTime = 1262152739; // Block #32255
pindexLast.nBits = 0x1d00ffff;
- BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1d00d86a);
+ BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, chainParams->GetConsensus()), 0x1d00d86a);
}
/* Test the constraint on the upper bound for next work */
BOOST_AUTO_TEST_CASE(get_next_work_pow_limit)
{
- SelectParams(CBaseChainParams::MAIN);
- const Consensus::Params& params = Params().GetConsensus();
-
+ const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);
int64_t nLastRetargetTime = 1231006505; // Block #0
CBlockIndex pindexLast;
pindexLast.nHeight = 2015;
pindexLast.nTime = 1233061996; // Block #2015
pindexLast.nBits = 0x1d00ffff;
- BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1d00ffff);
+ BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, chainParams->GetConsensus()), 0x1d00ffff);
}
/* Test the constraint on the lower bound for actual time taken */
BOOST_AUTO_TEST_CASE(get_next_work_lower_limit_actual)
{
- SelectParams(CBaseChainParams::MAIN);
- const Consensus::Params& params = Params().GetConsensus();
-
+ const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);
int64_t nLastRetargetTime = 1279008237; // Block #66528
CBlockIndex pindexLast;
pindexLast.nHeight = 68543;
pindexLast.nTime = 1279297671; // Block #68543
pindexLast.nBits = 0x1c05a3f4;
- BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1c0168fd);
+ BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, chainParams->GetConsensus()), 0x1c0168fd);
}
/* Test the constraint on the upper bound for actual time taken */
BOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual)
{
- SelectParams(CBaseChainParams::MAIN);
- const Consensus::Params& params = Params().GetConsensus();
-
+ const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);
int64_t nLastRetargetTime = 1263163443; // NOTE: Not an actual block time
CBlockIndex pindexLast;
pindexLast.nHeight = 46367;
pindexLast.nTime = 1269211443; // Block #46367
pindexLast.nBits = 0x1c387f6f;
- BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1d00e1fd);
+ BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, chainParams->GetConsensus()), 0x1d00e1fd);
}
BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test)
{
- SelectParams(CBaseChainParams::MAIN);
- const Consensus::Params& params = Params().GetConsensus();
-
+ const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);
std::vector<CBlockIndex> blocks(10000);
for (int i = 0; i < 10000; i++) {
- blocks[i].pprev = i ? &blocks[i - 1] : NULL;
+ blocks[i].pprev = i ? &blocks[i - 1] : nullptr;
blocks[i].nHeight = i;
- blocks[i].nTime = 1269211443 + i * params.nPowTargetSpacing;
+ blocks[i].nTime = 1269211443 + i * chainParams->GetConsensus().nPowTargetSpacing;
blocks[i].nBits = 0x207fffff; /* target 0x7fffff000... */
blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + GetBlockProof(blocks[i - 1]) : arith_uint256(0);
}
for (int j = 0; j < 1000; j++) {
- CBlockIndex *p1 = &blocks[GetRand(10000)];
- CBlockIndex *p2 = &blocks[GetRand(10000)];
- CBlockIndex *p3 = &blocks[GetRand(10000)];
+ CBlockIndex *p1 = &blocks[InsecureRandRange(10000)];
+ CBlockIndex *p2 = &blocks[InsecureRandRange(10000)];
+ CBlockIndex *p3 = &blocks[InsecureRandRange(10000)];
- int64_t tdiff = GetBlockProofEquivalentTime(*p1, *p2, *p3, params);
+ int64_t tdiff = GetBlockProofEquivalentTime(*p1, *p2, *p3, chainParams->GetConsensus());
BOOST_CHECK_EQUAL(tdiff, p1->GetBlockTime() - p2->GetBlockTime());
}
}
diff --git a/src/test/prevector_tests.cpp b/src/test/prevector_tests.cpp
index bd8a7819a4..841282873f 100644
--- a/src/test/prevector_tests.cpp
+++ b/src/test/prevector_tests.cpp
@@ -5,11 +5,11 @@
#include <vector>
#include "prevector.h"
+#include "reverse_iterator.h"
#include "serialize.h"
#include "streams.h"
#include "test/test_bitcoin.h"
-#include "test/test_random.h"
#include <boost/test/unit_test.hpp>
@@ -28,6 +28,7 @@ class prevector_tester {
typedef typename pretype::size_type Size;
bool passed = true;
FastRandomContext rand_cache;
+ uint256 rand_seed;
template <typename A, typename B>
@@ -53,16 +54,16 @@ class prevector_tester {
local_check(pretype(real_vector.begin(), real_vector.end()) == pre_vector);
local_check(pretype(pre_vector.begin(), pre_vector.end()) == pre_vector);
size_t pos = 0;
- BOOST_FOREACH(const T& v, pre_vector) {
+ for (const T& v : pre_vector) {
local_check(v == real_vector[pos++]);
}
- BOOST_REVERSE_FOREACH(const T& v, pre_vector) {
+ for (const T& v : reverse_iterate(pre_vector)) {
local_check(v == real_vector[--pos]);
}
- BOOST_FOREACH(const T& v, const_pre_vector) {
+ for (const T& v : const_pre_vector) {
local_check(v == real_vector[pos++]);
}
- BOOST_REVERSE_FOREACH(const T& v, const_pre_vector) {
+ for (const T& v : reverse_iterate(const_pre_vector)) {
local_check(v == real_vector[--pos]);
}
CDataStream ss1(SER_DISK, 0);
@@ -151,11 +152,11 @@ public:
pre_vector.assign(n, value);
}
- Size size() {
+ Size size() const {
return real_vector.size();
}
- Size capacity() {
+ Size capacity() const {
return pre_vector.capacity();
}
@@ -183,13 +184,12 @@ public:
}
~prevector_tester() {
- BOOST_CHECK_MESSAGE(passed, "insecure_rand_Rz: "
- << rand_cache.Rz
- << ", insecure_rand_Rw: "
- << rand_cache.Rw);
+ BOOST_CHECK_MESSAGE(passed, "insecure_rand: " + rand_seed.ToString());
}
+
prevector_tester() {
- seed_insecure_rand();
+ SeedInsecureRand();
+ rand_seed = insecure_rand_seed;
rand_cache = insecure_rand_ctx;
}
};
@@ -199,67 +199,65 @@ BOOST_AUTO_TEST_CASE(PrevectorTestInt)
for (int j = 0; j < 64; j++) {
prevector_tester<8, int> test;
for (int i = 0; i < 2048; i++) {
- int r = insecure_rand();
- if ((r % 4) == 0) {
- test.insert(insecure_rand() % (test.size() + 1), insecure_rand());
+ if (InsecureRandBits(2) == 0) {
+ test.insert(InsecureRandRange(test.size() + 1), InsecureRand32());
}
- if (test.size() > 0 && ((r >> 2) % 4) == 1) {
- test.erase(insecure_rand() % test.size());
+ if (test.size() > 0 && InsecureRandBits(2) == 1) {
+ test.erase(InsecureRandRange(test.size()));
}
- if (((r >> 4) % 8) == 2) {
- int new_size = std::max<int>(0, std::min<int>(30, test.size() + (insecure_rand() % 5) - 2));
+ if (InsecureRandBits(3) == 2) {
+ int new_size = std::max<int>(0, std::min<int>(30, test.size() + (InsecureRandRange(5)) - 2));
test.resize(new_size);
}
- if (((r >> 7) % 8) == 3) {
- test.insert(insecure_rand() % (test.size() + 1), 1 + (insecure_rand() % 2), insecure_rand());
+ if (InsecureRandBits(3) == 3) {
+ test.insert(InsecureRandRange(test.size() + 1), 1 + InsecureRandBool(), InsecureRand32());
}
- if (((r >> 10) % 8) == 4) {
- int del = std::min<int>(test.size(), 1 + (insecure_rand() % 2));
- int beg = insecure_rand() % (test.size() + 1 - del);
+ if (InsecureRandBits(3) == 4) {
+ int del = std::min<int>(test.size(), 1 + (InsecureRandBool()));
+ int beg = InsecureRandRange(test.size() + 1 - del);
test.erase(beg, beg + del);
}
- if (((r >> 13) % 16) == 5) {
- test.push_back(insecure_rand());
+ if (InsecureRandBits(4) == 5) {
+ test.push_back(InsecureRand32());
}
- if (test.size() > 0 && ((r >> 17) % 16) == 6) {
+ if (test.size() > 0 && InsecureRandBits(4) == 6) {
test.pop_back();
}
- if (((r >> 21) % 32) == 7) {
+ if (InsecureRandBits(5) == 7) {
int values[4];
- int num = 1 + (insecure_rand() % 4);
+ int num = 1 + (InsecureRandBits(2));
for (int k = 0; k < num; k++) {
- values[k] = insecure_rand();
+ values[k] = InsecureRand32();
}
- test.insert_range(insecure_rand() % (test.size() + 1), values, values + num);
+ test.insert_range(InsecureRandRange(test.size() + 1), values, values + num);
}
- if (((r >> 26) % 32) == 8) {
- int del = std::min<int>(test.size(), 1 + (insecure_rand() % 4));
- int beg = insecure_rand() % (test.size() + 1 - del);
+ if (InsecureRandBits(5) == 8) {
+ int del = std::min<int>(test.size(), 1 + (InsecureRandBits(2)));
+ int beg = InsecureRandRange(test.size() + 1 - del);
test.erase(beg, beg + del);
}
- r = insecure_rand();
- if (r % 32 == 9) {
- test.reserve(insecure_rand() % 32);
+ if (InsecureRandBits(5) == 9) {
+ test.reserve(InsecureRandBits(5));
}
- if ((r >> 5) % 64 == 10) {
+ if (InsecureRandBits(6) == 10) {
test.shrink_to_fit();
}
if (test.size() > 0) {
- test.update(insecure_rand() % test.size(), insecure_rand());
+ test.update(InsecureRandRange(test.size()), InsecureRand32());
}
- if (((r >> 11) % 1024) == 11) {
+ if (InsecureRandBits(10) == 11) {
test.clear();
}
- if (((r >> 21) % 512) == 12) {
- test.assign(insecure_rand() % 32, insecure_rand());
+ if (InsecureRandBits(9) == 12) {
+ test.assign(InsecureRandBits(5), InsecureRand32());
}
- if (((r >> 15) % 8) == 3) {
+ if (InsecureRandBits(3) == 3) {
test.swap();
}
- if (((r >> 15) % 16) == 8) {
+ if (InsecureRandBits(4) == 8) {
test.copy();
}
- if (((r >> 15) % 32) == 18) {
+ if (InsecureRandBits(5) == 18) {
test.move();
}
}
diff --git a/src/test/raii_event_tests.cpp b/src/test/raii_event_tests.cpp
index 87d25c0e2c..0d541ec7d4 100644
--- a/src/test/raii_event_tests.cpp
+++ b/src/test/raii_event_tests.cpp
@@ -3,6 +3,10 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <event2/event.h>
+
+#ifdef EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED
+// It would probably be ideal to define dummy test(s) that report skipped, but boost::test doesn't seem to make that practical (at least not in versions available with common distros)
+
#include <map>
#include <stdlib.h>
@@ -38,7 +42,7 @@ BOOST_AUTO_TEST_CASE(raii_event_creation)
{
event_set_mem_functions(tag_malloc, realloc, tag_free);
- void* base_ptr = NULL;
+ void* base_ptr = nullptr;
{
auto base = obtain_event_base();
base_ptr = (void*)base.get();
@@ -46,10 +50,10 @@ BOOST_AUTO_TEST_CASE(raii_event_creation)
}
BOOST_CHECK(tags[base_ptr] == 0);
- void* event_ptr = NULL;
+ void* event_ptr = nullptr;
{
auto base = obtain_event_base();
- auto event = obtain_event(base.get(), -1, 0, NULL, NULL);
+ auto event = obtain_event(base.get(), -1, 0, nullptr, nullptr);
base_ptr = (void*)base.get();
event_ptr = (void*)event.get();
@@ -67,11 +71,11 @@ BOOST_AUTO_TEST_CASE(raii_event_order)
{
event_set_mem_functions(tag_malloc, realloc, tag_free);
- void* base_ptr = NULL;
- void* event_ptr = NULL;
+ void* base_ptr = nullptr;
+ void* event_ptr = nullptr;
{
auto base = obtain_event_base();
- auto event = obtain_event(base.get(), -1, 0, NULL, NULL);
+ auto event = obtain_event(base.get(), -1, 0, nullptr, nullptr);
base_ptr = (void*)base.get();
event_ptr = (void*)event.get();
@@ -86,3 +90,5 @@ BOOST_AUTO_TEST_CASE(raii_event_order)
}
BOOST_AUTO_TEST_SUITE_END()
+
+#endif // EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED
diff --git a/src/test/random_tests.cpp b/src/test/random_tests.cpp
new file mode 100644
index 0000000000..132e190051
--- /dev/null
+++ b/src/test/random_tests.cpp
@@ -0,0 +1,60 @@
+// Copyright (c) 2017 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 "test/test_bitcoin.h"
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_FIXTURE_TEST_SUITE(random_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(osrandom_tests)
+{
+ BOOST_CHECK(Random_SanityCheck());
+}
+
+BOOST_AUTO_TEST_CASE(fastrandom_tests)
+{
+ // Check that deterministic FastRandomContexts are deterministic
+ FastRandomContext ctx1(true);
+ FastRandomContext ctx2(true);
+
+ BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());
+ BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());
+ BOOST_CHECK_EQUAL(ctx1.rand64(), ctx2.rand64());
+ BOOST_CHECK_EQUAL(ctx1.randbits(3), ctx2.randbits(3));
+ BOOST_CHECK(ctx1.randbytes(17) == ctx2.randbytes(17));
+ BOOST_CHECK(ctx1.rand256() == ctx2.rand256());
+ BOOST_CHECK_EQUAL(ctx1.randbits(7), ctx2.randbits(7));
+ BOOST_CHECK(ctx1.randbytes(128) == ctx2.randbytes(128));
+ BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());
+ BOOST_CHECK_EQUAL(ctx1.randbits(3), ctx2.randbits(3));
+ BOOST_CHECK(ctx1.rand256() == ctx2.rand256());
+ BOOST_CHECK(ctx1.randbytes(50) == ctx2.randbytes(50));
+
+ // Check that a nondeterministic ones are not
+ FastRandomContext ctx3;
+ FastRandomContext ctx4;
+ BOOST_CHECK(ctx3.rand64() != ctx4.rand64()); // extremely unlikely to be equal
+ BOOST_CHECK(ctx3.rand256() != ctx4.rand256());
+ BOOST_CHECK(ctx3.randbytes(7) != ctx4.randbytes(7));
+}
+
+BOOST_AUTO_TEST_CASE(fastrandom_randbits)
+{
+ FastRandomContext ctx1;
+ FastRandomContext ctx2;
+ for (int bits = 0; bits < 63; ++bits) {
+ for (int j = 0; j < 1000; ++j) {
+ uint64_t rangebits = ctx1.randbits(bits);
+ BOOST_CHECK_EQUAL(rangebits >> bits, 0);
+ uint64_t range = ((uint64_t)1) << bits | rangebits;
+ uint64_t rand = ctx2.randrange(range);
+ BOOST_CHECK(rand < range);
+ }
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index 399bdbc811..c6643be7a7 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -6,12 +6,12 @@
#include "rpc/client.h"
#include "base58.h"
+#include "core_io.h"
#include "netbase.h"
#include "test/test_bitcoin.h"
#include <boost/algorithm/string.hpp>
-#include <boost/assign/list_of.hpp>
#include <boost/test/unit_test.hpp>
#include <univalue.h>
@@ -276,7 +276,7 @@ BOOST_AUTO_TEST_CASE(rpc_ban)
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
+ // must throw an exception because 127.0.0.1 is in already banned subnet range
BOOST_CHECK_THROW(r = CallRPC(std::string("setban 127.0.0.1 add")), std::runtime_error);
BOOST_CHECK_NO_THROW(CallRPC(std::string("setban 127.0.0.0/24 remove")));
@@ -324,20 +324,20 @@ BOOST_AUTO_TEST_CASE(rpc_convert_values_generatetoaddress)
{
UniValue result;
- BOOST_CHECK_NO_THROW(result = RPCConvertValues("generatetoaddress", boost::assign::list_of("101")("mkESjLZW66TmHhiFX8MCaBjrhZ543PPh9a")));
+ BOOST_CHECK_NO_THROW(result = RPCConvertValues("generatetoaddress", {"101", "mkESjLZW66TmHhiFX8MCaBjrhZ543PPh9a"}));
BOOST_CHECK_EQUAL(result[0].get_int(), 101);
BOOST_CHECK_EQUAL(result[1].get_str(), "mkESjLZW66TmHhiFX8MCaBjrhZ543PPh9a");
- BOOST_CHECK_NO_THROW(result = RPCConvertValues("generatetoaddress", boost::assign::list_of("101")("mhMbmE2tE9xzJYCV9aNC8jKWN31vtGrguU")));
+ BOOST_CHECK_NO_THROW(result = RPCConvertValues("generatetoaddress", {"101", "mhMbmE2tE9xzJYCV9aNC8jKWN31vtGrguU"}));
BOOST_CHECK_EQUAL(result[0].get_int(), 101);
BOOST_CHECK_EQUAL(result[1].get_str(), "mhMbmE2tE9xzJYCV9aNC8jKWN31vtGrguU");
- BOOST_CHECK_NO_THROW(result = RPCConvertValues("generatetoaddress", boost::assign::list_of("1")("mkESjLZW66TmHhiFX8MCaBjrhZ543PPh9a")("9")));
+ BOOST_CHECK_NO_THROW(result = RPCConvertValues("generatetoaddress", {"1", "mkESjLZW66TmHhiFX8MCaBjrhZ543PPh9a", "9"}));
BOOST_CHECK_EQUAL(result[0].get_int(), 1);
BOOST_CHECK_EQUAL(result[1].get_str(), "mkESjLZW66TmHhiFX8MCaBjrhZ543PPh9a");
BOOST_CHECK_EQUAL(result[2].get_int(), 9);
- BOOST_CHECK_NO_THROW(result = RPCConvertValues("generatetoaddress", boost::assign::list_of("1")("mhMbmE2tE9xzJYCV9aNC8jKWN31vtGrguU")("9")));
+ BOOST_CHECK_NO_THROW(result = RPCConvertValues("generatetoaddress", {"1", "mhMbmE2tE9xzJYCV9aNC8jKWN31vtGrguU", "9"}));
BOOST_CHECK_EQUAL(result[0].get_int(), 1);
BOOST_CHECK_EQUAL(result[1].get_str(), "mhMbmE2tE9xzJYCV9aNC8jKWN31vtGrguU");
BOOST_CHECK_EQUAL(result[2].get_int(), 9);
diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp
index e1b0ab9258..1de865776e 100644
--- a/src/test/scheduler_tests.cpp
+++ b/src/test/scheduler_tests.cpp
@@ -8,8 +8,6 @@
#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>
@@ -47,8 +45,8 @@ BOOST_AUTO_TEST_CASE(manythreads)
//
// 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
+ // Each task adds or subtracts a random amount from one of the
+ // counters, 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.
@@ -56,10 +54,10 @@ BOOST_AUTO_TEST_CASE(manythreads)
boost::mutex counterMutex[10];
int counter[10] = { 0 };
- boost::random::mt19937 rng(42);
- boost::random::uniform_int_distribution<> zeroToNine(0, 9);
- boost::random::uniform_int_distribution<> randomMsec(-11, 1000);
- boost::random::uniform_int_distribution<> randomDelta(-1000, 1000);
+ FastRandomContext rng(42);
+ auto zeroToNine = [](FastRandomContext& rc) -> int { return rc.randrange(10); }; // [0, 9]
+ auto randomMsec = [](FastRandomContext& rc) -> int { return -11 + rc.randrange(1012); }; // [-11, 1000]
+ auto randomDelta = [](FastRandomContext& rc) -> int { return -1000 + rc.randrange(2001); }; // [-1000, 1000]
boost::chrono::system_clock::time_point start = boost::chrono::system_clock::now();
boost::chrono::system_clock::time_point now = start;
diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp
index f8fd8cc30c..58aa32c969 100644
--- a/src/test/script_P2SH_tests.cpp
+++ b/src/test/script_P2SH_tests.cpp
@@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "consensus/tx_verify.h"
#include "core_io.h"
#include "key.h"
#include "keystore.h"
@@ -41,7 +42,7 @@ Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, Scri
txTo.vin[0].scriptSig = scriptSig;
txTo.vout[0].nValue = 1;
- return VerifyScript(scriptSig, scriptPubKey, NULL, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, 0, txFrom.vout[0].nValue), &err);
+ return VerifyScript(scriptSig, scriptPubKey, nullptr, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, 0, txFrom.vout[0].nValue), &err);
}
@@ -111,7 +112,7 @@ BOOST_AUTO_TEST_CASE(sign)
{
CScript sigSave = txTo[i].vin[0].scriptSig;
txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig;
- bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false, &txdata)();
+ bool sigOK = CScriptCheck(txFrom.vout[txTo[i].vin[0].prevout.n], txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false, &txdata)();
if (i == j)
BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j));
else
@@ -315,7 +316,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txFrom.vout[6].scriptPubKey = GetScriptForDestination(CScriptID(twentySigops));
txFrom.vout[6].nValue = 6000;
- coins.ModifyCoins(txFrom.GetHash())->FromTx(txFrom, 0);
+ AddCoins(coins, txFrom, 0);
CMutableTransaction txTo;
txTo.vout.resize(1);
diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp
new file mode 100644
index 0000000000..bd2d9ed115
--- /dev/null
+++ b/src/test/script_standard_tests.cpp
@@ -0,0 +1,741 @@
+// Copyright (c) 2017 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 "key.h"
+#include "keystore.h"
+#include "script/ismine.h"
+#include "script/script.h"
+#include "script/script_error.h"
+#include "script/standard.h"
+#include "test/test_bitcoin.h"
+
+#include <boost/test/unit_test.hpp>
+
+
+BOOST_FIXTURE_TEST_SUITE(script_standard_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
+{
+ CKey keys[3];
+ CPubKey pubkeys[3];
+ for (int i = 0; i < 3; i++) {
+ keys[i].MakeNewKey(true);
+ pubkeys[i] = keys[i].GetPubKey();
+ }
+
+ CScript s;
+ txnouttype whichType;
+ std::vector<std::vector<unsigned char> > solutions;
+
+ // TX_PUBKEY
+ s.clear();
+ s << ToByteVector(pubkeys[0]) << OP_CHECKSIG;
+ BOOST_CHECK(Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(whichType, TX_PUBKEY);
+ BOOST_CHECK_EQUAL(solutions.size(), 1);
+ BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0]));
+
+ // TX_PUBKEYHASH
+ s.clear();
+ s << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
+ BOOST_CHECK(Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(whichType, TX_PUBKEYHASH);
+ BOOST_CHECK_EQUAL(solutions.size(), 1);
+ BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0].GetID()));
+
+ // TX_SCRIPTHASH
+ CScript redeemScript(s); // initialize with leftover P2PKH script
+ s.clear();
+ s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
+ BOOST_CHECK(Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(whichType, TX_SCRIPTHASH);
+ BOOST_CHECK_EQUAL(solutions.size(), 1);
+ BOOST_CHECK(solutions[0] == ToByteVector(CScriptID(redeemScript)));
+
+ // TX_MULTISIG
+ s.clear();
+ s << OP_1 <<
+ ToByteVector(pubkeys[0]) <<
+ ToByteVector(pubkeys[1]) <<
+ OP_2 << OP_CHECKMULTISIG;
+ BOOST_CHECK(Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(whichType, TX_MULTISIG);
+ BOOST_CHECK_EQUAL(solutions.size(), 4);
+ BOOST_CHECK(solutions[0] == std::vector<unsigned char>({1}));
+ BOOST_CHECK(solutions[1] == ToByteVector(pubkeys[0]));
+ BOOST_CHECK(solutions[2] == ToByteVector(pubkeys[1]));
+ BOOST_CHECK(solutions[3] == std::vector<unsigned char>({2}));
+
+ s.clear();
+ s << OP_2 <<
+ ToByteVector(pubkeys[0]) <<
+ ToByteVector(pubkeys[1]) <<
+ ToByteVector(pubkeys[2]) <<
+ OP_3 << OP_CHECKMULTISIG;
+ BOOST_CHECK(Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(whichType, TX_MULTISIG);
+ BOOST_CHECK_EQUAL(solutions.size(), 5);
+ BOOST_CHECK(solutions[0] == std::vector<unsigned char>({2}));
+ BOOST_CHECK(solutions[1] == ToByteVector(pubkeys[0]));
+ BOOST_CHECK(solutions[2] == ToByteVector(pubkeys[1]));
+ BOOST_CHECK(solutions[3] == ToByteVector(pubkeys[2]));
+ BOOST_CHECK(solutions[4] == std::vector<unsigned char>({3}));
+
+ // TX_NULL_DATA
+ s.clear();
+ s << OP_RETURN <<
+ std::vector<unsigned char>({0}) <<
+ std::vector<unsigned char>({75}) <<
+ std::vector<unsigned char>({255});
+ BOOST_CHECK(Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(whichType, TX_NULL_DATA);
+ BOOST_CHECK_EQUAL(solutions.size(), 0);
+
+ // TX_WITNESS_V0_KEYHASH
+ s.clear();
+ s << OP_0 << ToByteVector(pubkeys[0].GetID());
+ BOOST_CHECK(Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(whichType, TX_WITNESS_V0_KEYHASH);
+ BOOST_CHECK_EQUAL(solutions.size(), 1);
+ BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0].GetID()));
+
+ // TX_WITNESS_V0_SCRIPTHASH
+ uint256 scriptHash;
+ CSHA256().Write(&redeemScript[0], redeemScript.size())
+ .Finalize(scriptHash.begin());
+
+ s.clear();
+ s << OP_0 << ToByteVector(scriptHash);
+ BOOST_CHECK(Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(whichType, TX_WITNESS_V0_SCRIPTHASH);
+ BOOST_CHECK_EQUAL(solutions.size(), 1);
+ BOOST_CHECK(solutions[0] == ToByteVector(scriptHash));
+
+ // TX_NONSTANDARD
+ s.clear();
+ s << OP_9 << OP_ADD << OP_11 << OP_EQUAL;
+ BOOST_CHECK(!Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(whichType, TX_NONSTANDARD);
+}
+
+BOOST_AUTO_TEST_CASE(script_standard_Solver_failure)
+{
+ CKey key;
+ CPubKey pubkey;
+ key.MakeNewKey(true);
+ pubkey = key.GetPubKey();
+
+ CScript s;
+ txnouttype whichType;
+ std::vector<std::vector<unsigned char> > solutions;
+
+ // TX_PUBKEY with incorrectly sized pubkey
+ s.clear();
+ s << std::vector<unsigned char>(30, 0x01) << OP_CHECKSIG;
+ BOOST_CHECK(!Solver(s, whichType, solutions));
+
+ // TX_PUBKEYHASH with incorrectly sized key hash
+ s.clear();
+ s << OP_DUP << OP_HASH160 << ToByteVector(pubkey) << OP_EQUALVERIFY << OP_CHECKSIG;
+ BOOST_CHECK(!Solver(s, whichType, solutions));
+
+ // TX_SCRIPTHASH with incorrectly sized script hash
+ s.clear();
+ s << OP_HASH160 << std::vector<unsigned char>(21, 0x01) << OP_EQUAL;
+ BOOST_CHECK(!Solver(s, whichType, solutions));
+
+ // TX_MULTISIG 0/2
+ s.clear();
+ s << OP_0 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG;
+ BOOST_CHECK(!Solver(s, whichType, solutions));
+
+ // TX_MULTISIG 2/1
+ s.clear();
+ s << OP_2 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG;
+ BOOST_CHECK(!Solver(s, whichType, solutions));
+
+ // TX_MULTISIG n = 2 with 1 pubkey
+ s.clear();
+ s << OP_1 << ToByteVector(pubkey) << OP_2 << OP_CHECKMULTISIG;
+ BOOST_CHECK(!Solver(s, whichType, solutions));
+
+ // TX_MULTISIG n = 1 with 0 pubkeys
+ s.clear();
+ s << OP_1 << OP_1 << OP_CHECKMULTISIG;
+ BOOST_CHECK(!Solver(s, whichType, solutions));
+
+ // TX_NULL_DATA with other opcodes
+ s.clear();
+ s << OP_RETURN << std::vector<unsigned char>({75}) << OP_ADD;
+ BOOST_CHECK(!Solver(s, whichType, solutions));
+
+ // TX_WITNESS with incorrect program size
+ s.clear();
+ s << OP_0 << std::vector<unsigned char>(19, 0x01);
+ BOOST_CHECK(!Solver(s, whichType, solutions));
+}
+
+BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
+{
+ CKey key;
+ CPubKey pubkey;
+ key.MakeNewKey(true);
+ pubkey = key.GetPubKey();
+
+ CScript s;
+ CTxDestination address;
+
+ // TX_PUBKEY
+ s.clear();
+ s << ToByteVector(pubkey) << OP_CHECKSIG;
+ BOOST_CHECK(ExtractDestination(s, address));
+ BOOST_CHECK(boost::get<CKeyID>(&address) &&
+ *boost::get<CKeyID>(&address) == pubkey.GetID());
+
+ // TX_PUBKEYHASH
+ s.clear();
+ s << OP_DUP << OP_HASH160 << ToByteVector(pubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
+ BOOST_CHECK(ExtractDestination(s, address));
+ BOOST_CHECK(boost::get<CKeyID>(&address) &&
+ *boost::get<CKeyID>(&address) == pubkey.GetID());
+
+ // TX_SCRIPTHASH
+ CScript redeemScript(s); // initialize with leftover P2PKH script
+ s.clear();
+ s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
+ BOOST_CHECK(ExtractDestination(s, address));
+ BOOST_CHECK(boost::get<CScriptID>(&address) &&
+ *boost::get<CScriptID>(&address) == CScriptID(redeemScript));
+
+ // TX_MULTISIG
+ s.clear();
+ s << OP_1 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG;
+ BOOST_CHECK(!ExtractDestination(s, address));
+
+ // TX_NULL_DATA
+ s.clear();
+ s << OP_RETURN << std::vector<unsigned char>({75});
+ BOOST_CHECK(!ExtractDestination(s, address));
+
+ // TX_WITNESS_V0_KEYHASH
+ s.clear();
+ s << OP_0 << ToByteVector(pubkey.GetID());
+ BOOST_CHECK(ExtractDestination(s, address));
+ WitnessV0KeyHash keyhash;
+ CHash160().Write(pubkey.begin(), pubkey.size()).Finalize(keyhash.begin());
+ BOOST_CHECK(boost::get<WitnessV0KeyHash>(&address) && *boost::get<WitnessV0KeyHash>(&address) == keyhash);
+
+ // TX_WITNESS_V0_SCRIPTHASH
+ s.clear();
+ WitnessV0ScriptHash scripthash;
+ CSHA256().Write(redeemScript.data(), redeemScript.size()).Finalize(scripthash.begin());
+ s << OP_0 << ToByteVector(scripthash);
+ BOOST_CHECK(ExtractDestination(s, address));
+ BOOST_CHECK(boost::get<WitnessV0ScriptHash>(&address) && *boost::get<WitnessV0ScriptHash>(&address) == scripthash);
+
+ // TX_WITNESS with unknown version
+ s.clear();
+ s << OP_1 << ToByteVector(pubkey);
+ BOOST_CHECK(ExtractDestination(s, address));
+ WitnessUnknown unk;
+ unk.length = 33;
+ unk.version = 1;
+ std::copy(pubkey.begin(), pubkey.end(), unk.program);
+ BOOST_CHECK(boost::get<WitnessUnknown>(&address) && *boost::get<WitnessUnknown>(&address) == unk);
+}
+
+BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations)
+{
+ CKey keys[3];
+ CPubKey pubkeys[3];
+ for (int i = 0; i < 3; i++) {
+ keys[i].MakeNewKey(true);
+ pubkeys[i] = keys[i].GetPubKey();
+ }
+
+ CScript s;
+ txnouttype whichType;
+ std::vector<CTxDestination> addresses;
+ int nRequired;
+
+ // TX_PUBKEY
+ s.clear();
+ s << ToByteVector(pubkeys[0]) << OP_CHECKSIG;
+ BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired));
+ BOOST_CHECK_EQUAL(whichType, TX_PUBKEY);
+ BOOST_CHECK_EQUAL(addresses.size(), 1);
+ BOOST_CHECK_EQUAL(nRequired, 1);
+ BOOST_CHECK(boost::get<CKeyID>(&addresses[0]) &&
+ *boost::get<CKeyID>(&addresses[0]) == pubkeys[0].GetID());
+
+ // TX_PUBKEYHASH
+ s.clear();
+ s << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
+ BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired));
+ BOOST_CHECK_EQUAL(whichType, TX_PUBKEYHASH);
+ BOOST_CHECK_EQUAL(addresses.size(), 1);
+ BOOST_CHECK_EQUAL(nRequired, 1);
+ BOOST_CHECK(boost::get<CKeyID>(&addresses[0]) &&
+ *boost::get<CKeyID>(&addresses[0]) == pubkeys[0].GetID());
+
+ // TX_SCRIPTHASH
+ CScript redeemScript(s); // initialize with leftover P2PKH script
+ s.clear();
+ s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
+ BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired));
+ BOOST_CHECK_EQUAL(whichType, TX_SCRIPTHASH);
+ BOOST_CHECK_EQUAL(addresses.size(), 1);
+ BOOST_CHECK_EQUAL(nRequired, 1);
+ BOOST_CHECK(boost::get<CScriptID>(&addresses[0]) &&
+ *boost::get<CScriptID>(&addresses[0]) == CScriptID(redeemScript));
+
+ // TX_MULTISIG
+ s.clear();
+ s << OP_2 <<
+ ToByteVector(pubkeys[0]) <<
+ ToByteVector(pubkeys[1]) <<
+ OP_2 << OP_CHECKMULTISIG;
+ BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired));
+ BOOST_CHECK_EQUAL(whichType, TX_MULTISIG);
+ BOOST_CHECK_EQUAL(addresses.size(), 2);
+ BOOST_CHECK_EQUAL(nRequired, 2);
+ BOOST_CHECK(boost::get<CKeyID>(&addresses[0]) &&
+ *boost::get<CKeyID>(&addresses[0]) == pubkeys[0].GetID());
+ BOOST_CHECK(boost::get<CKeyID>(&addresses[1]) &&
+ *boost::get<CKeyID>(&addresses[1]) == pubkeys[1].GetID());
+
+ // TX_NULL_DATA
+ s.clear();
+ s << OP_RETURN << std::vector<unsigned char>({75});
+ BOOST_CHECK(!ExtractDestinations(s, whichType, addresses, nRequired));
+}
+
+BOOST_AUTO_TEST_CASE(script_standard_GetScriptFor_)
+{
+ CKey keys[3];
+ CPubKey pubkeys[3];
+ for (int i = 0; i < 3; i++) {
+ keys[i].MakeNewKey(true);
+ pubkeys[i] = keys[i].GetPubKey();
+ }
+
+ CScript expected, result;
+
+ // CKeyID
+ expected.clear();
+ expected << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
+ result = GetScriptForDestination(pubkeys[0].GetID());
+ BOOST_CHECK(result == expected);
+
+ // CScriptID
+ CScript redeemScript(result);
+ expected.clear();
+ expected << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
+ result = GetScriptForDestination(CScriptID(redeemScript));
+ BOOST_CHECK(result == expected);
+
+ // CNoDestination
+ expected.clear();
+ result = GetScriptForDestination(CNoDestination());
+ BOOST_CHECK(result == expected);
+
+ // GetScriptForRawPubKey
+ expected.clear();
+ expected << ToByteVector(pubkeys[0]) << OP_CHECKSIG;
+ result = GetScriptForRawPubKey(pubkeys[0]);
+ BOOST_CHECK(result == expected);
+
+ // GetScriptForMultisig
+ expected.clear();
+ expected << OP_2 <<
+ ToByteVector(pubkeys[0]) <<
+ ToByteVector(pubkeys[1]) <<
+ ToByteVector(pubkeys[2]) <<
+ OP_3 << OP_CHECKMULTISIG;
+ result = GetScriptForMultisig(2, std::vector<CPubKey>(pubkeys, pubkeys + 3));
+ BOOST_CHECK(result == expected);
+
+ // GetScriptForWitness
+ CScript witnessScript;
+
+ witnessScript << ToByteVector(pubkeys[0]) << OP_CHECKSIG;
+ expected.clear();
+ expected << OP_0 << ToByteVector(pubkeys[0].GetID());
+ result = GetScriptForWitness(witnessScript);
+ BOOST_CHECK(result == expected);
+
+ witnessScript.clear();
+ witnessScript << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
+ result = GetScriptForWitness(witnessScript);
+ BOOST_CHECK(result == expected);
+
+ witnessScript.clear();
+ witnessScript << OP_1 << ToByteVector(pubkeys[0]) << OP_1 << OP_CHECKMULTISIG;
+
+ uint256 scriptHash;
+ CSHA256().Write(&witnessScript[0], witnessScript.size())
+ .Finalize(scriptHash.begin());
+
+ expected.clear();
+ expected << OP_0 << ToByteVector(scriptHash);
+ result = GetScriptForWitness(witnessScript);
+ BOOST_CHECK(result == expected);
+}
+
+BOOST_AUTO_TEST_CASE(script_standard_IsMine)
+{
+ CKey keys[2];
+ CPubKey pubkeys[2];
+ for (int i = 0; i < 2; i++) {
+ keys[i].MakeNewKey(true);
+ pubkeys[i] = keys[i].GetPubKey();
+ }
+
+ CKey uncompressedKey;
+ uncompressedKey.MakeNewKey(false);
+ CPubKey uncompressedPubkey = uncompressedKey.GetPubKey();
+
+ CScript scriptPubKey;
+ isminetype result;
+ bool isInvalid;
+
+ // P2PK compressed
+ {
+ CBasicKeyStore keystore;
+ scriptPubKey.clear();
+ scriptPubKey << ToByteVector(pubkeys[0]) << OP_CHECKSIG;
+
+ // Keystore does not have key
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has key
+ keystore.AddKey(keys[0]);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(!isInvalid);
+ }
+
+ // P2PK uncompressed
+ {
+ CBasicKeyStore keystore;
+ scriptPubKey.clear();
+ scriptPubKey << ToByteVector(uncompressedPubkey) << OP_CHECKSIG;
+
+ // Keystore does not have key
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has key
+ keystore.AddKey(uncompressedKey);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(!isInvalid);
+ }
+
+ // P2PKH compressed
+ {
+ CBasicKeyStore keystore;
+ scriptPubKey.clear();
+ scriptPubKey << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
+
+ // Keystore does not have key
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has key
+ keystore.AddKey(keys[0]);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(!isInvalid);
+ }
+
+ // P2PKH uncompressed
+ {
+ CBasicKeyStore keystore;
+ scriptPubKey.clear();
+ scriptPubKey << OP_DUP << OP_HASH160 << ToByteVector(uncompressedPubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
+
+ // Keystore does not have key
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has key
+ keystore.AddKey(uncompressedKey);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(!isInvalid);
+ }
+
+ // P2SH
+ {
+ CBasicKeyStore keystore;
+
+ CScript redeemScript;
+ redeemScript << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
+
+ // Keystore does not have redeemScript or key
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has redeemScript but no key
+ keystore.AddCScript(redeemScript);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has redeemScript and key
+ keystore.AddKey(keys[0]);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(!isInvalid);
+ }
+
+ // P2WPKH compressed
+ {
+ CBasicKeyStore keystore;
+ keystore.AddKey(keys[0]);
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_0 << ToByteVector(pubkeys[0].GetID());
+
+ // Keystore has key, but no P2SH redeemScript
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has key and P2SH redeemScript
+ keystore.AddCScript(scriptPubKey);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(!isInvalid);
+ }
+
+ // P2WPKH uncompressed
+ {
+ CBasicKeyStore keystore;
+ keystore.AddKey(uncompressedKey);
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_0 << ToByteVector(uncompressedPubkey.GetID());
+
+ // Keystore has key, but no P2SH redeemScript
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has key and P2SH redeemScript
+ keystore.AddCScript(scriptPubKey);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(isInvalid);
+ }
+
+ // scriptPubKey multisig
+ {
+ CBasicKeyStore keystore;
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_2 <<
+ ToByteVector(uncompressedPubkey) <<
+ ToByteVector(pubkeys[1]) <<
+ OP_2 << OP_CHECKMULTISIG;
+
+ // Keystore does not have any keys
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has 1/2 keys
+ keystore.AddKey(uncompressedKey);
+
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has 2/2 keys
+ keystore.AddKey(keys[1]);
+
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(!isInvalid);
+ }
+
+ // P2SH multisig
+ {
+ CBasicKeyStore keystore;
+ keystore.AddKey(uncompressedKey);
+ keystore.AddKey(keys[1]);
+
+ CScript redeemScript;
+ redeemScript << OP_2 <<
+ ToByteVector(uncompressedPubkey) <<
+ ToByteVector(pubkeys[1]) <<
+ OP_2 << OP_CHECKMULTISIG;
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
+
+ // Keystore has no redeemScript
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has redeemScript
+ keystore.AddCScript(redeemScript);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(!isInvalid);
+ }
+
+ // P2WSH multisig with compressed keys
+ {
+ CBasicKeyStore keystore;
+ keystore.AddKey(keys[0]);
+ keystore.AddKey(keys[1]);
+
+ CScript witnessScript;
+ witnessScript << OP_2 <<
+ ToByteVector(pubkeys[0]) <<
+ ToByteVector(pubkeys[1]) <<
+ OP_2 << OP_CHECKMULTISIG;
+
+ uint256 scriptHash;
+ CSHA256().Write(&witnessScript[0], witnessScript.size())
+ .Finalize(scriptHash.begin());
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_0 << ToByteVector(scriptHash);
+
+ // Keystore has keys, but no witnessScript or P2SH redeemScript
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has keys and witnessScript, but no P2SH redeemScript
+ keystore.AddCScript(witnessScript);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has keys, witnessScript, P2SH redeemScript
+ keystore.AddCScript(scriptPubKey);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(!isInvalid);
+ }
+
+ // P2WSH multisig with uncompressed key
+ {
+ CBasicKeyStore keystore;
+ keystore.AddKey(uncompressedKey);
+ keystore.AddKey(keys[1]);
+
+ CScript witnessScript;
+ witnessScript << OP_2 <<
+ ToByteVector(uncompressedPubkey) <<
+ ToByteVector(pubkeys[1]) <<
+ OP_2 << OP_CHECKMULTISIG;
+
+ uint256 scriptHash;
+ CSHA256().Write(&witnessScript[0], witnessScript.size())
+ .Finalize(scriptHash.begin());
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_0 << ToByteVector(scriptHash);
+
+ // Keystore has keys, but no witnessScript or P2SH redeemScript
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has keys and witnessScript, but no P2SH redeemScript
+ keystore.AddCScript(witnessScript);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has keys, witnessScript, P2SH redeemScript
+ keystore.AddCScript(scriptPubKey);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(isInvalid);
+ }
+
+ // P2WSH multisig wrapped in P2SH
+ {
+ CBasicKeyStore keystore;
+
+ CScript witnessScript;
+ witnessScript << OP_2 <<
+ ToByteVector(pubkeys[0]) <<
+ ToByteVector(pubkeys[1]) <<
+ OP_2 << OP_CHECKMULTISIG;
+
+ uint256 scriptHash;
+ CSHA256().Write(&witnessScript[0], witnessScript.size())
+ .Finalize(scriptHash.begin());
+
+ CScript redeemScript;
+ redeemScript << OP_0 << ToByteVector(scriptHash);
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
+
+ // Keystore has no witnessScript, P2SH redeemScript, or keys
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has witnessScript and P2SH redeemScript, but no keys
+ keystore.AddCScript(redeemScript);
+ keystore.AddCScript(witnessScript);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+
+ // Keystore has keys, witnessScript, P2SH redeemScript
+ keystore.AddKey(keys[0]);
+ keystore.AddKey(keys[1]);
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ BOOST_CHECK(!isInvalid);
+ }
+
+ // OP_RETURN
+ {
+ CBasicKeyStore keystore;
+ keystore.AddKey(keys[0]);
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_RETURN << ToByteVector(pubkeys[0]);
+
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+ }
+
+ // Nonstandard
+ {
+ CBasicKeyStore keystore;
+ keystore.AddKey(keys[0]);
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_9 << OP_ADD << OP_11 << OP_EQUAL;
+
+ result = IsMine(keystore, scriptPubKey, isInvalid);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ BOOST_CHECK(!isInvalid);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 6f057f43b4..011a5db795 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -24,7 +24,6 @@
#include <string>
#include <vector>
-#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
#include <univalue.h>
@@ -32,7 +31,7 @@
// Uncomment if you want to output updated JSON tests.
// #define UPDATE_JSON_TESTS
-static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
+static const unsigned int gFlags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
unsigned int ParseScriptFlags(std::string strFlags);
std::string FormatScriptFlags(unsigned int flags);
@@ -173,10 +172,10 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScript
int libconsensus_flags = flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_ALL;
if (libconsensus_flags == flags) {
if (flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS) {
- BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(scriptPubKey.data(), scriptPubKey.size(), txCredit.vout[0].nValue, (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, NULL) == expect, message);
+ BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(scriptPubKey.data(), scriptPubKey.size(), txCredit.vout[0].nValue, (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, nullptr) == expect, message);
} else {
- BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(scriptPubKey.data(), scriptPubKey.size(), 0, (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, NULL) == expect, message);
- BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, NULL) == expect,message);
+ BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(scriptPubKey.data(), scriptPubKey.size(), 0, (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, nullptr) == expect, message);
+ BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, nullptr) == expect,message);
}
}
#endif
@@ -451,21 +450,16 @@ public:
return array;
}
- std::string GetComment()
+ std::string GetComment() const
{
return comment;
}
-
- const CScript& GetScriptPubKey()
- {
- return creditTx->vout[0].scriptPubKey;
- }
};
std::string JSONPrettyPrint(const UniValue& univalue)
{
std::string ret = univalue.write(4);
- // Workaround for libunivalue pretty printer, which puts a space between comma's and newlines
+ // Workaround for libunivalue pretty printer, which puts a space between commas and newlines
size_t pos = 0;
while ((pos = ret.find(" \n", pos)) != std::string::npos) {
ret.replace(pos, 2, "\n");
@@ -473,7 +467,7 @@ std::string JSONPrettyPrint(const UniValue& univalue)
}
return ret;
}
-}
+} // namespace
BOOST_AUTO_TEST_CASE(script_build)
{
@@ -932,7 +926,7 @@ BOOST_AUTO_TEST_CASE(script_build)
std::string strGen;
- BOOST_FOREACH(TestBuilder& test, tests) {
+ for (TestBuilder& test : tests) {
test.Test();
std::string str = JSONPrettyPrint(test.GetJSON());
#ifndef UPDATE_JSON_TESTS
@@ -1038,7 +1032,7 @@ sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transac
// and vice-versa)
//
result << OP_0;
- BOOST_FOREACH(const CKey &key, keys)
+ for (const CKey &key : keys)
{
std::vector<unsigned char> vchSig;
BOOST_CHECK(key.Sign(hash, vchSig));
@@ -1070,18 +1064,18 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), CScriptWitness(), txFrom12);
CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12);
- BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, NULL, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err));
+ BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
txTo12.vout[0].nValue = 2;
- BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, NULL, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err));
+ BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12);
- BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, NULL, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err));
+ BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12);
- BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, NULL, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err));
+ BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
}
@@ -1103,54 +1097,54 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
std::vector<CKey> keys;
keys.push_back(key1); keys.push_back(key2);
CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
- BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
+ BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
keys.clear();
keys.push_back(key1); keys.push_back(key3);
CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23);
- BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
+ BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
keys.clear();
keys.push_back(key2); keys.push_back(key3);
CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23);
- BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
+ BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
keys.clear();
keys.push_back(key2); keys.push_back(key2); // Can't re-use sig
CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
- BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
+ BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear();
keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order
CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23);
- BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
+ BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear();
keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order
CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23);
- BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
+ BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear();
keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys
CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23);
- BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
+ BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear();
keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys
CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23);
- BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
+ BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear(); // Must have signatures
CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23);
- BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
+ BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
}
@@ -1271,7 +1265,7 @@ BOOST_AUTO_TEST_CASE(script_standard_push)
CScript script;
script << i;
BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Number " << i << " is not pure push.");
- BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, NULL, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), "Number " << i << " push is not minimal data.");
+ BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, nullptr, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), "Number " << i << " push is not minimal data.");
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
}
@@ -1280,7 +1274,7 @@ BOOST_AUTO_TEST_CASE(script_standard_push)
CScript script;
script << data;
BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Length " << i << " is not pure push.");
- BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, NULL, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), "Length " << i << " push is not minimal data.");
+ BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, nullptr, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), "Length " << i << " push is not minimal data.");
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
}
}
@@ -1443,4 +1437,35 @@ BOOST_AUTO_TEST_CASE(script_FindAndDelete)
BOOST_CHECK(s == expect);
}
+BOOST_AUTO_TEST_CASE(script_HasValidOps)
+{
+ // Exercise the HasValidOps functionality
+ CScript script;
+ script = ScriptFromHex("76a9141234567890abcdefa1a2a3a4a5a6a7a8a9a0aaab88ac"); // Normal script
+ BOOST_CHECK(script.HasValidOps());
+ script = ScriptFromHex("76a914ff34567890abcdefa1a2a3a4a5a6a7a8a9a0aaab88ac");
+ BOOST_CHECK(script.HasValidOps());
+ script = ScriptFromHex("ff88ac"); // Script with OP_INVALIDOPCODE explicit
+ BOOST_CHECK(!script.HasValidOps());
+ script = ScriptFromHex("88acc0"); // Script with undefined opcode
+ BOOST_CHECK(!script.HasValidOps());
+}
+
+BOOST_AUTO_TEST_CASE(script_can_append_self)
+{
+ CScript s, d;
+
+ s = ScriptFromHex("00");
+ s += s;
+ d = ScriptFromHex("0000");
+ BOOST_CHECK(s == d);
+
+ // check doubling a script that's large enough to require reallocation
+ static const char hex[] = "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f";
+ s = CScript() << ParseHex(hex) << OP_CHECKSIG;
+ d = CScript() << ParseHex(hex) << OP_CHECKSIG << ParseHex(hex) << OP_CHECKSIG;
+ s += s;
+ BOOST_CHECK(s == d);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/scriptnum_tests.cpp b/src/test/scriptnum_tests.cpp
index 6b6689c7d3..280eb59ce8 100644
--- a/src/test/scriptnum_tests.cpp
+++ b/src/test/scriptnum_tests.cpp
@@ -12,8 +12,10 @@
BOOST_FIXTURE_TEST_SUITE(scriptnum_tests, BasicTestingSetup)
-static const int64_t values[] = \
-{ 0, 1, CHAR_MIN, CHAR_MAX, UCHAR_MAX, SHRT_MIN, USHRT_MAX, INT_MIN, INT_MAX, UINT_MAX, LONG_MIN, LONG_MAX };
+/** A selection of numbers that do not trigger int64_t overflow
+ * when added/subtracted. */
+static const int64_t values[] = { 0, 1, -2, 127, 128, -255, 256, (1LL << 15) - 1, -(1LL << 16), (1LL << 24) - 1, (1LL << 31), 1 - (1LL << 32), 1LL << 40 };
+
static const int64_t offsets[] = { 1, 0x79, 0x80, 0x81, 0xFF, 0x7FFF, 0x8000, 0xFFFF, 0x10000};
static bool verify(const CScriptNum10& bignum, const CScriptNum& scriptnum)
@@ -27,10 +29,7 @@ static void CheckCreateVch(const int64_t& num)
CScriptNum scriptnum(num);
BOOST_CHECK(verify(bignum, scriptnum));
- std::vector<unsigned char> vch = bignum.getvch();
-
CScriptNum10 bignum2(bignum.getvch(), false);
- vch = scriptnum.getvch();
CScriptNum scriptnum2(scriptnum.getvch(), false);
BOOST_CHECK(verify(bignum2, scriptnum2));
@@ -88,11 +87,10 @@ static void CheckSubtract(const int64_t& num1, const int64_t& num2)
const CScriptNum10 bignum2(num2);
const CScriptNum scriptnum1(num1);
const CScriptNum scriptnum2(num2);
- bool invalid = false;
// int64_t overflow is undefined.
- invalid = ((num2 > 0 && num1 < std::numeric_limits<int64_t>::min() + num2) ||
- (num2 < 0 && num1 > std::numeric_limits<int64_t>::max() + num2));
+ bool invalid = ((num2 > 0 && num1 < std::numeric_limits<int64_t>::min() + num2) ||
+ (num2 < 0 && num1 > std::numeric_limits<int64_t>::max() + num2));
if (!invalid)
{
BOOST_CHECK(verify(bignum1 - bignum2, scriptnum1 - scriptnum2));
diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp
index 2d54668eaf..9661a66514 100644
--- a/src/test/serialize_tests.cpp
+++ b/src/test/serialize_tests.cpp
@@ -90,7 +90,7 @@ BOOST_AUTO_TEST_CASE(sizes)
BOOST_AUTO_TEST_CASE(floats_conversion)
{
- // Choose values that map unambigiously to binary floating point to avoid
+ // Choose values that map unambiguously to binary floating point to avoid
// rounding issues at the compiler side.
BOOST_CHECK_EQUAL(ser_uint32_to_float(0x00000000), 0.0F);
BOOST_CHECK_EQUAL(ser_uint32_to_float(0x3f000000), 0.5F);
@@ -109,7 +109,7 @@ BOOST_AUTO_TEST_CASE(floats_conversion)
BOOST_AUTO_TEST_CASE(doubles_conversion)
{
- // Choose values that map unambigiously to binary floating point to avoid
+ // Choose values that map unambiguously to binary floating point to avoid
// rounding issues at the compiler side.
BOOST_CHECK_EQUAL(ser_uint64_to_double(0x0000000000000000ULL), 0.0);
BOOST_CHECK_EQUAL(ser_uint64_to_double(0x3fe0000000000000ULL), 0.5);
diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp
index 5279cb243b..ecbdf57788 100644
--- a/src/test/sighash_tests.cpp
+++ b/src/test/sighash_tests.cpp
@@ -2,16 +2,15 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "consensus/tx_verify.h"
#include "consensus/validation.h"
#include "data/sighash.json.h"
#include "hash.h"
-#include "validation.h" // For CheckTransaction
#include "script/interpreter.h"
#include "script/script.h"
#include "serialize.h"
#include "streams.h"
#include "test/test_bitcoin.h"
-#include "test/test_random.h"
#include "util.h"
#include "utilstrencodings.h"
#include "version.h"
@@ -30,7 +29,6 @@ uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, un
static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
if (nIn >= txTo.vin.size())
{
- printf("ERROR: SignatureHash(): nIn=%d out of range\n", nIn);
return one;
}
CMutableTransaction txTmp(txTo);
@@ -61,7 +59,6 @@ uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, un
unsigned int nOut = nIn;
if (nOut >= txTmp.vout.size())
{
- printf("ERROR: SignatureHash(): nOut=%d out of range\n", nOut);
return one;
}
txTmp.vout.resize(nOut+1);
@@ -90,30 +87,30 @@ uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, un
void static RandomScript(CScript &script) {
static const opcodetype oplist[] = {OP_FALSE, OP_1, OP_2, OP_3, OP_CHECKSIG, OP_IF, OP_VERIF, OP_RETURN, OP_CODESEPARATOR};
script = CScript();
- int ops = (insecure_rand() % 10);
+ int ops = (InsecureRandRange(10));
for (int i=0; i<ops; i++)
- script << oplist[insecure_rand() % (sizeof(oplist)/sizeof(oplist[0]))];
+ script << oplist[InsecureRandRange(sizeof(oplist)/sizeof(oplist[0]))];
}
void static RandomTransaction(CMutableTransaction &tx, bool fSingle) {
- tx.nVersion = insecure_rand();
+ tx.nVersion = InsecureRand32();
tx.vin.clear();
tx.vout.clear();
- tx.nLockTime = (insecure_rand() % 2) ? insecure_rand() : 0;
- int ins = (insecure_rand() % 4) + 1;
- int outs = fSingle ? ins : (insecure_rand() % 4) + 1;
+ tx.nLockTime = (InsecureRandBool()) ? InsecureRand32() : 0;
+ int ins = (InsecureRandBits(2)) + 1;
+ int outs = fSingle ? ins : (InsecureRandBits(2)) + 1;
for (int in = 0; in < ins; in++) {
tx.vin.push_back(CTxIn());
CTxIn &txin = tx.vin.back();
- txin.prevout.hash = GetRandHash();
- txin.prevout.n = insecure_rand() % 4;
+ txin.prevout.hash = InsecureRand256();
+ txin.prevout.n = InsecureRandBits(2);
RandomScript(txin.scriptSig);
- txin.nSequence = (insecure_rand() % 2) ? insecure_rand() : (unsigned int)-1;
+ txin.nSequence = (InsecureRandBool()) ? InsecureRand32() : (unsigned int)-1;
}
for (int out = 0; out < outs; out++) {
tx.vout.push_back(CTxOut());
CTxOut &txout = tx.vout.back();
- txout.nValue = insecure_rand() % 100000000;
+ txout.nValue = InsecureRandRange(100000000);
RandomScript(txout.scriptPubKey);
}
}
@@ -122,24 +119,22 @@ BOOST_FIXTURE_TEST_SUITE(sighash_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(sighash_test)
{
- seed_insecure_rand(false);
+ SeedInsecureRand(false);
#if defined(PRINT_SIGHASH_JSON)
std::cout << "[\n";
std::cout << "\t[\"raw_transaction, script, input_index, hashType, signature_hash (result)\"],\n";
- #endif
+ int nRandomTests = 500;
+ #else
int nRandomTests = 50000;
-
- #if defined(PRINT_SIGHASH_JSON)
- nRandomTests = 500;
#endif
for (int i=0; i<nRandomTests; i++) {
- int nHashType = insecure_rand();
+ int nHashType = InsecureRand32();
CMutableTransaction txTo;
RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE);
CScript scriptCode;
RandomScript(scriptCode);
- int nIn = insecure_rand() % txTo.vin.size();
+ int nIn = InsecureRandRange(txTo.vin.size());
uint256 sh, sho;
sho = SignatureHashOld(scriptCode, txTo, nIn, nHashType);
diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp
index 13d8911f03..d3b8b07228 100644
--- a/src/test/sigopcount_tests.cpp
+++ b/src/test/sigopcount_tests.cpp
@@ -2,7 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "validation.h"
+#include "consensus/tx_verify.h"
+#include "consensus/validation.h"
#include "pubkey.h"
#include "key.h"
#include "script/script.h"
@@ -12,7 +13,6 @@
#include <vector>
-#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
// Helpers:
@@ -102,7 +102,7 @@ void BuildTxs(CMutableTransaction& spendingTx, CCoinsViewCache& coins, CMutableT
spendingTx.vout[0].nValue = 1;
spendingTx.vout[0].scriptPubKey = CScript();
- coins.ModifyCoins(creationTx.GetHash())->FromTx(creationTx, 0);
+ AddCoins(coins, creationTx, 0);
}
BOOST_AUTO_TEST_CASE(GetTxSigOpCost)
diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp
index 0b2fe0ef9d..164cbd873f 100644
--- a/src/test/skiplist_tests.cpp
+++ b/src/test/skiplist_tests.cpp
@@ -5,7 +5,6 @@
#include "chain.h"
#include "util.h"
#include "test/test_bitcoin.h"
-#include "test/test_random.h"
#include <vector>
@@ -21,7 +20,7 @@ BOOST_AUTO_TEST_CASE(skiplist_test)
for (int i=0; i<SKIPLIST_LENGTH; i++) {
vIndex[i].nHeight = i;
- vIndex[i].pprev = (i == 0) ? NULL : &vIndex[i - 1];
+ vIndex[i].pprev = (i == 0) ? nullptr : &vIndex[i - 1];
vIndex[i].BuildSkip();
}
@@ -30,17 +29,17 @@ BOOST_AUTO_TEST_CASE(skiplist_test)
BOOST_CHECK(vIndex[i].pskip == &vIndex[vIndex[i].pskip->nHeight]);
BOOST_CHECK(vIndex[i].pskip->nHeight < i);
} else {
- BOOST_CHECK(vIndex[i].pskip == NULL);
+ BOOST_CHECK(vIndex[i].pskip == nullptr);
}
}
for (int i=0; i < 1000; i++) {
- int from = insecure_rand() % (SKIPLIST_LENGTH - 1);
- int to = insecure_rand() % (from + 1);
+ int from = InsecureRandRange(SKIPLIST_LENGTH - 1);
+ int to = InsecureRandRange(from + 1);
BOOST_CHECK(vIndex[SKIPLIST_LENGTH - 1].GetAncestor(from) == &vIndex[from]);
BOOST_CHECK(vIndex[from].GetAncestor(to) == &vIndex[to]);
- BOOST_CHECK(vIndex[from].GetAncestor(0) == &vIndex[0]);
+ BOOST_CHECK(vIndex[from].GetAncestor(0) == vIndex.data());
}
}
@@ -52,11 +51,11 @@ BOOST_AUTO_TEST_CASE(getlocator_test)
for (unsigned int i=0; i<vBlocksMain.size(); i++) {
vHashMain[i] = ArithToUint256(i); // Set the hash equal to the height, so we can quickly check the distances.
vBlocksMain[i].nHeight = i;
- vBlocksMain[i].pprev = i ? &vBlocksMain[i - 1] : NULL;
+ vBlocksMain[i].pprev = i ? &vBlocksMain[i - 1] : nullptr;
vBlocksMain[i].phashBlock = &vHashMain[i];
vBlocksMain[i].BuildSkip();
BOOST_CHECK_EQUAL((int)UintToArith256(vBlocksMain[i].GetBlockHash()).GetLow64(), vBlocksMain[i].nHeight);
- BOOST_CHECK(vBlocksMain[i].pprev == NULL || vBlocksMain[i].nHeight == vBlocksMain[i].pprev->nHeight + 1);
+ BOOST_CHECK(vBlocksMain[i].pprev == nullptr || vBlocksMain[i].nHeight == vBlocksMain[i].pprev->nHeight + 1);
}
// Build a branch that splits off at block 49999, 50000 blocks long.
@@ -65,11 +64,11 @@ BOOST_AUTO_TEST_CASE(getlocator_test)
for (unsigned int i=0; i<vBlocksSide.size(); i++) {
vHashSide[i] = ArithToUint256(i + 50000 + (arith_uint256(1) << 128)); // Add 1<<128 to the hashes, so GetLow64() still returns the height.
vBlocksSide[i].nHeight = i + 50000;
- vBlocksSide[i].pprev = i ? &vBlocksSide[i - 1] : &vBlocksMain[49999];
+ vBlocksSide[i].pprev = i ? &vBlocksSide[i - 1] : (vBlocksMain.data()+49999);
vBlocksSide[i].phashBlock = &vHashSide[i];
vBlocksSide[i].BuildSkip();
BOOST_CHECK_EQUAL((int)UintToArith256(vBlocksSide[i].GetBlockHash()).GetLow64(), vBlocksSide[i].nHeight);
- BOOST_CHECK(vBlocksSide[i].pprev == NULL || vBlocksSide[i].nHeight == vBlocksSide[i].pprev->nHeight + 1);
+ BOOST_CHECK(vBlocksSide[i].pprev == nullptr || vBlocksSide[i].nHeight == vBlocksSide[i].pprev->nHeight + 1);
}
// Build a CChain for the main branch.
@@ -78,7 +77,7 @@ BOOST_AUTO_TEST_CASE(getlocator_test)
// Test 100 random starting points for locators.
for (int n=0; n<100; n++) {
- int r = insecure_rand() % 150000;
+ int r = InsecureRandRange(150000);
CBlockIndex* tip = (r < 100000) ? &vBlocksMain[r] : &vBlocksSide[r - 100000];
CBlockLocator locator = chain.GetLocator(tip);
@@ -107,7 +106,7 @@ BOOST_AUTO_TEST_CASE(findearliestatleast_test)
for (unsigned int i=0; i<vBlocksMain.size(); i++) {
vHashMain[i] = ArithToUint256(i); // Set the hash equal to the height
vBlocksMain[i].nHeight = i;
- vBlocksMain[i].pprev = i ? &vBlocksMain[i - 1] : NULL;
+ vBlocksMain[i].pprev = i ? &vBlocksMain[i - 1] : nullptr;
vBlocksMain[i].phashBlock = &vHashMain[i];
vBlocksMain[i].BuildSkip();
if (i < 10) {
@@ -116,7 +115,7 @@ BOOST_AUTO_TEST_CASE(findearliestatleast_test)
} else {
// randomly choose something in the range [MTP, MTP*2]
int64_t medianTimePast = vBlocksMain[i].GetMedianTimePast();
- int r = insecure_rand() % medianTimePast;
+ int r = InsecureRandRange(medianTimePast);
vBlocksMain[i].nTime = r + medianTimePast;
vBlocksMain[i].nTimeMax = std::max(vBlocksMain[i].nTime, vBlocksMain[i-1].nTimeMax);
}
@@ -135,12 +134,47 @@ BOOST_AUTO_TEST_CASE(findearliestatleast_test)
// Verify that FindEarliestAtLeast is correct.
for (unsigned int i=0; i<10000; ++i) {
// Pick a random element in vBlocksMain.
- int r = insecure_rand() % vBlocksMain.size();
+ int r = InsecureRandRange(vBlocksMain.size());
int64_t test_time = vBlocksMain[r].nTime;
CBlockIndex *ret = chain.FindEarliestAtLeast(test_time);
BOOST_CHECK(ret->nTimeMax >= test_time);
- BOOST_CHECK((ret->pprev==NULL) || ret->pprev->nTimeMax < test_time);
+ BOOST_CHECK((ret->pprev==nullptr) || ret->pprev->nTimeMax < test_time);
BOOST_CHECK(vBlocksMain[r].GetAncestor(ret->nHeight) == ret);
}
}
+
+BOOST_AUTO_TEST_CASE(findearliestatleast_edge_test)
+{
+ std::list<CBlockIndex> blocks;
+ for (unsigned int timeMax : {100, 100, 100, 200, 200, 200, 300, 300, 300}) {
+ CBlockIndex* prev = blocks.empty() ? nullptr : &blocks.back();
+ blocks.emplace_back();
+ blocks.back().nHeight = prev ? prev->nHeight + 1 : 0;
+ blocks.back().pprev = prev;
+ blocks.back().BuildSkip();
+ blocks.back().nTimeMax = timeMax;
+ }
+
+ CChain chain;
+ chain.SetTip(&blocks.back());
+
+ BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(50)->nHeight, 0);
+ BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(100)->nHeight, 0);
+ BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(150)->nHeight, 3);
+ BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(200)->nHeight, 3);
+ BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(250)->nHeight, 6);
+ BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(300)->nHeight, 6);
+ BOOST_CHECK(!chain.FindEarliestAtLeast(350));
+
+ BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(0)->nHeight, 0);
+ BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(-1)->nHeight, 0);
+
+ BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(std::numeric_limits<int64_t>::min())->nHeight, 0);
+ BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(std::numeric_limits<unsigned int>::min())->nHeight, 0);
+ BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(-int64_t(std::numeric_limits<unsigned int>::max()) - 1)->nHeight, 0);
+ BOOST_CHECK(!chain.FindEarliestAtLeast(std::numeric_limits<int64_t>::max()));
+ BOOST_CHECK(!chain.FindEarliestAtLeast(std::numeric_limits<unsigned int>::max()));
+ BOOST_CHECK(!chain.FindEarliestAtLeast(int64_t(std::numeric_limits<unsigned int>::max()) + 1));
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp
index 94b5cc119b..af2a152aa5 100644
--- a/src/test/streams_tests.cpp
+++ b/src/test/streams_tests.cpp
@@ -7,7 +7,6 @@
#include "test/test_bitcoin.h"
#include <boost/assign/std/vector.hpp> // for 'operator+=()'
-#include <boost/assert.hpp>
#include <boost/test/unit_test.hpp>
using namespace boost::assign; // bring 'operator+=()' into scope
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index f0eaab2217..79bc48a118 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#define BOOST_TEST_MODULE Bitcoin Test Suite
-
#include "test_bitcoin.h"
#include "chainparams.h"
#include "consensus/consensus.h"
#include "consensus/validation.h"
+#include "crypto/sha256.h"
+#include "fs.h"
#include "key.h"
#include "validation.h"
#include "miner.h"
@@ -18,30 +18,28 @@
#include "txdb.h"
#include "txmempool.h"
#include "ui_interface.h"
+#include "streams.h"
#include "rpc/server.h"
#include "rpc/register.h"
#include "script/sigcache.h"
-#include "test/testutil.h"
-
#include <memory>
-#include <boost/filesystem.hpp>
-#include <boost/test/unit_test.hpp>
-#include <boost/thread.hpp>
-
-std::unique_ptr<CConnman> g_connman;
-FastRandomContext insecure_rand_ctx(true);
+uint256 insecure_rand_seed = GetRandHash();
+FastRandomContext insecure_rand_ctx(insecure_rand_seed);
extern bool fPrintToConsole;
extern void noui_connect();
BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
{
+ SHA256AutoDetect();
+ RandomInit();
ECC_Start();
SetupEnvironment();
SetupNetworking();
InitSignatureCache();
+ InitScriptExecutionCache();
fPrintToDebugLog = false; // don't want to write to debug.log file
fCheckBlockIndex = true;
SelectParams(chainName);
@@ -51,7 +49,6 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
BasicTestingSetup::~BasicTestingSetup()
{
ECC_Stop();
- g_connman.reset();
}
TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(chainName)
@@ -62,37 +59,49 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
RegisterAllCoreRPCCommands(tableRPC);
ClearDatadirCache();
- pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000)));
- boost::filesystem::create_directories(pathTemp);
- ForceSetArg("-datadir", pathTemp.string());
+ pathTemp = fs::temp_directory_path() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(InsecureRandRange(100000)));
+ fs::create_directories(pathTemp);
+ gArgs.ForceSetArg("-datadir", pathTemp.string());
+
+ // Note that because we don't bother running a scheduler thread here,
+ // callbacks via CValidationInterface are unreliable, but that's OK,
+ // our unit tests aren't testing multiple parts of the code at once.
+ GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
+
mempool.setSanityCheck(1.0);
pblocktree = new CBlockTreeDB(1 << 20, true);
pcoinsdbview = new CCoinsViewDB(1 << 23, true);
pcoinsTip = new CCoinsViewCache(pcoinsdbview);
- InitBlockIndex(chainparams);
+ if (!LoadGenesisBlock(chainparams)) {
+ throw std::runtime_error("LoadGenesisBlock failed.");
+ }
{
CValidationState state;
- bool ok = ActivateBestChain(state, chainparams);
- BOOST_CHECK(ok);
+ if (!ActivateBestChain(state, chainparams)) {
+ throw std::runtime_error("ActivateBestChain failed.");
+ }
}
nScriptCheckThreads = 3;
for (int i=0; i < nScriptCheckThreads-1; i++)
threadGroup.create_thread(&ThreadScriptCheck);
g_connman = std::unique_ptr<CConnman>(new CConnman(0x1337, 0x1337)); // Deterministic randomness for tests.
connman = g_connman.get();
- RegisterNodeSignals(GetNodeSignals());
+ peerLogic.reset(new PeerLogicValidation(connman));
}
TestingSetup::~TestingSetup()
{
- UnregisterNodeSignals(GetNodeSignals());
threadGroup.interrupt_all();
threadGroup.join_all();
+ GetMainSignals().FlushBackgroundCallbacks();
+ GetMainSignals().UnregisterBackgroundSignalScheduler();
+ g_connman.reset();
+ peerLogic.reset();
UnloadBlockIndex();
delete pcoinsTip;
delete pcoinsdbview;
delete pblocktree;
- boost::filesystem::remove_all(pathTemp);
+ fs::remove_all(pathTemp);
}
TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST)
@@ -121,7 +130,7 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>&
// Replace mempool-selected txns with just coinbase plus passed-in txns:
block.vtx.resize(1);
- BOOST_FOREACH(const CMutableTransaction& tx, txns)
+ for (const CMutableTransaction& tx : txns)
block.vtx.push_back(MakeTransactionRef(tx));
// IncrementExtraNonce creates a valid coinbase and merkleRoot
unsigned int extraNonce = 0;
@@ -130,7 +139,7 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>&
while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce;
std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(block);
- ProcessNewBlock(chainparams, shared_pblock, true, NULL);
+ ProcessNewBlock(chainparams, shared_pblock, true, nullptr);
CBlock result = block;
return result;
@@ -141,30 +150,24 @@ TestChain100Setup::~TestChain100Setup()
}
-CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx, CTxMemPool *pool) {
+CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx) {
CTransaction txn(tx);
- return FromTx(txn, pool);
+ return FromTx(txn);
}
-CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransaction &txn, CTxMemPool *pool) {
- // Hack to assume either its completely dependent on other mempool txs or not at all
- CAmount inChainValue = pool && pool->HasNoInputsOf(txn) ? txn.GetValueOut() : 0;
-
- return CTxMemPoolEntry(MakeTransactionRef(txn), nFee, nTime, dPriority, nHeight,
- inChainValue, spendsCoinbase, sigOpCost, lp);
-}
-
-void Shutdown(void* parg)
-{
- exit(0);
-}
-
-void StartShutdown()
-{
- exit(0);
+CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransaction &txn) {
+ return CTxMemPoolEntry(MakeTransactionRef(txn), nFee, nTime, nHeight,
+ spendsCoinbase, sigOpCost, lp);
}
-bool ShutdownRequested()
+/**
+ * @returns a real block (0000000000013b8ab2cd513b0261a14096412195a72a0c4827d229dcc7e0f7af)
+ * with 9 txs.
+ */
+CBlock getBlock13b8a()
{
- return false;
+ CBlock block;
+ CDataStream stream(ParseHex("0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb6800000000000005275289558f51c9966699404ae2294730c3c9f9bda53523ce50e9b95e558da2fdb261b4d4c86041b1ab1bf930901000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0146ffffffff0100f2052a01000000434104e18f7afbe4721580e81e8414fc8c24d7cfacf254bb5c7b949450c3e997c2dc1242487a8169507b631eb3771f2b425483fb13102c4eb5d858eef260fe70fbfae0ac00000000010000000196608ccbafa16abada902780da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100dab24889213caf43ae6adc41cf1c9396c08240c199f5225acf45416330fd7dbd022100fe37900e0644bf574493a07fc5edba06dbc07c311b947520c2d514bc5725dcb401ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369ed2fc393ce288ac000000000100000001fb766c1288458c2bafcfec81e48b24d98ec706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268ba165ce0ad2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21adc6c401887f2bfd1922f11d76159cbc597fbd756a23dcbb00f4d7290141042b4e8625a96127826915a5b109852636ad0da753c9e1d5606a50480cd0c40f1f8b8d898235e571fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff0280969800000000001976a9146963907531db72d0ed1a0cfb471ccb63923446f388ac80d6e34c000000001976a914f0688ba1c0d1ce182c7af6741e02658c7d4dfcd388ac000000000100000002c40297f730dd7b5a99567eb8d27b78758f607507c52292d02d4031895b52f2ff010000008b483045022100f7edfd4b0aac404e5bab4fd3889e0c6c41aa8d0e6fa122316f68eddd0a65013902205b09cc8b2d56e1cd1f7f2fafd60a129ed94504c4ac7bdc67b56fe67512658b3e014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffffca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb000000008a473044022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae740605658022006d1af525b9a14a35c003b78b72bd59738cd676f845d1ff3fc25049e01003614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffff01001ec4110200000043410469ab4181eceb28985b9b4e895c13fa5e68d85761b7eee311db5addef76fa8621865134a221bd01f28ec9999ee3e021e60766e9d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91c514655e2dc50633d1e4c84989f8aa90a0dbc883f0d23ed5c2fa010000008b48304502207ab51be6f12a1962ba0aaaf24a20e0b69b27a94fac5adf45aa7d2d18ffd9236102210086ae728b370e5329eead9accd880d0cb070aea0c96255fae6c4f1ddcce1fd56e014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad56529371864d9f6cb042faa06b588ac000000000100000001b4a47603e71b61bc3326efd90111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987dad92acb0c64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a038fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb6042034aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000"), SER_NETWORK, PROTOCOL_VERSION);
+ stream >> block;
+ return block;
}
diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h
index 5ef6fa764f..2390aca342 100644
--- a/src/test/test_bitcoin.h
+++ b/src/test/test_bitcoin.h
@@ -6,21 +6,42 @@
#define BITCOIN_TEST_TEST_BITCOIN_H
#include "chainparamsbase.h"
+#include "fs.h"
#include "key.h"
#include "pubkey.h"
+#include "random.h"
+#include "scheduler.h"
#include "txdb.h"
#include "txmempool.h"
-#include <boost/filesystem.hpp>
#include <boost/thread.hpp>
+extern uint256 insecure_rand_seed;
+extern FastRandomContext insecure_rand_ctx;
+
+static inline void SeedInsecureRand(bool fDeterministic = false)
+{
+ if (fDeterministic) {
+ insecure_rand_seed = uint256();
+ } else {
+ insecure_rand_seed = GetRandHash();
+ }
+ insecure_rand_ctx = FastRandomContext(insecure_rand_seed);
+}
+
+static inline uint32_t InsecureRand32() { return insecure_rand_ctx.rand32(); }
+static inline uint256 InsecureRand256() { return insecure_rand_ctx.rand256(); }
+static inline uint64_t InsecureRandBits(int bits) { return insecure_rand_ctx.randbits(bits); }
+static inline uint64_t InsecureRandRange(uint64_t range) { return insecure_rand_ctx.randrange(range); }
+static inline bool InsecureRandBool() { return insecure_rand_ctx.randbool(); }
+
/** Basic testing setup.
* This just configures logging and chain parameters.
*/
struct BasicTestingSetup {
ECCVerifyHandle globalVerifyHandle;
- BasicTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
+ explicit BasicTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
~BasicTestingSetup();
};
@@ -28,13 +49,16 @@ struct BasicTestingSetup {
* Included are data directory, coins database, script check threads setup.
*/
class CConnman;
+class PeerLogicValidation;
struct TestingSetup: public BasicTestingSetup {
CCoinsViewDB *pcoinsdbview;
- boost::filesystem::path pathTemp;
+ fs::path pathTemp;
boost::thread_group threadGroup;
CConnman* connman;
+ CScheduler scheduler;
+ std::unique_ptr<PeerLogicValidation> peerLogic;
- TestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
+ explicit TestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
~TestingSetup();
};
@@ -61,32 +85,32 @@ struct TestChain100Setup : public TestingSetup {
};
class CTxMemPoolEntry;
-class CTxMemPool;
struct TestMemPoolEntryHelper
{
// Default values
CAmount nFee;
int64_t nTime;
- double dPriority;
unsigned int nHeight;
bool spendsCoinbase;
unsigned int sigOpCost;
LockPoints lp;
TestMemPoolEntryHelper() :
- nFee(0), nTime(0), dPriority(0.0), nHeight(1),
+ nFee(0), nTime(0), nHeight(1),
spendsCoinbase(false), sigOpCost(4) { }
-
- CTxMemPoolEntry FromTx(const CMutableTransaction &tx, CTxMemPool *pool = NULL);
- CTxMemPoolEntry FromTx(const CTransaction &tx, CTxMemPool *pool = NULL);
+
+ CTxMemPoolEntry FromTx(const CMutableTransaction &tx);
+ CTxMemPoolEntry FromTx(const CTransaction &tx);
// Change the default value
TestMemPoolEntryHelper &Fee(CAmount _fee) { nFee = _fee; return *this; }
TestMemPoolEntryHelper &Time(int64_t _time) { nTime = _time; return *this; }
- TestMemPoolEntryHelper &Priority(double _priority) { dPriority = _priority; return *this; }
TestMemPoolEntryHelper &Height(unsigned int _height) { nHeight = _height; return *this; }
TestMemPoolEntryHelper &SpendsCoinbase(bool _flag) { spendsCoinbase = _flag; return *this; }
TestMemPoolEntryHelper &SigOpsCost(unsigned int _sigopsCost) { sigOpCost = _sigopsCost; return *this; }
};
+
+CBlock getBlock13b8a();
+
#endif
diff --git a/src/test/test_bitcoin_fuzzy.cpp b/src/test/test_bitcoin_fuzzy.cpp
index 376d8e428a..581ad2ffa0 100644
--- a/src/test/test_bitcoin_fuzzy.cpp
+++ b/src/test/test_bitcoin_fuzzy.cpp
@@ -18,6 +18,7 @@
#include "streams.h"
#include "undo.h"
#include "version.h"
+#include "pubkey.h"
#include <stdint.h>
#include <unistd.h>
@@ -47,8 +48,8 @@ enum TEST_ID {
TEST_ID_END
};
-bool read_stdin(std::vector<char> &data) {
- char buffer[1024];
+bool read_stdin(std::vector<uint8_t> &data) {
+ uint8_t buffer[1024];
ssize_t length=0;
while((length = read(STDIN_FILENO, buffer, 1024)) > 0) {
data.insert(data.end(), buffer, buffer+length);
@@ -58,15 +59,11 @@ bool read_stdin(std::vector<char> &data) {
return length==0;
}
-int main(int argc, char **argv)
-{
- std::vector<char> buffer;
- if (!read_stdin(buffer)) return 0;
-
+int test_one_input(std::vector<uint8_t> buffer) {
if (buffer.size() < sizeof(uint32_t)) return 0;
uint32_t test_id = 0xffffffff;
- memcpy(&test_id, &buffer[0], sizeof(uint32_t));
+ memcpy(&test_id, buffer.data(), sizeof(uint32_t));
buffer.erase(buffer.begin(), buffer.begin() + sizeof(uint32_t));
if (test_id >= TEST_ID_END) return 0;
@@ -167,8 +164,8 @@ int main(int argc, char **argv)
{
try
{
- CCoins block;
- ds >> block;
+ Coin coin;
+ ds >> coin;
} catch (const std::ios_base::failure& e) {return 0;}
break;
}
@@ -254,3 +251,55 @@ int main(int argc, char **argv)
return 0;
}
+static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle;
+void initialize() {
+ globalVerifyHandle = std::unique_ptr<ECCVerifyHandle>(new ECCVerifyHandle());
+}
+
+// This function is used by libFuzzer
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ test_one_input(std::vector<uint8_t>(data, data + size));
+ return 0;
+}
+
+// This function is used by libFuzzer
+extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
+ initialize();
+ return 0;
+}
+
+// Disabled under WIN32 due to clash with Cygwin's WinMain.
+#ifndef WIN32
+// Declare main(...) "weak" to allow for libFuzzer linking. libFuzzer provides
+// the main(...) function.
+__attribute__((weak))
+#endif
+int main(int argc, char **argv)
+{
+ initialize();
+#ifdef __AFL_INIT
+ // Enable AFL deferred forkserver mode. Requires compilation using
+ // afl-clang-fast++. See fuzzing.md for details.
+ __AFL_INIT();
+#endif
+
+#ifdef __AFL_LOOP
+ // Enable AFL persistent mode. Requires compilation using afl-clang-fast++.
+ // See fuzzing.md for details.
+ int ret = 0;
+ while (__AFL_LOOP(1000)) {
+ std::vector<uint8_t> buffer;
+ if (!read_stdin(buffer)) {
+ continue;
+ }
+ ret = test_one_input(buffer);
+ }
+ return ret;
+#else
+ std::vector<uint8_t> buffer;
+ if (!read_stdin(buffer)) {
+ return 0;
+ }
+ return test_one_input(buffer);
+#endif
+}
diff --git a/src/test/test_bitcoin_main.cpp b/src/test/test_bitcoin_main.cpp
new file mode 100644
index 0000000000..b556c953b9
--- /dev/null
+++ b/src/test/test_bitcoin_main.cpp
@@ -0,0 +1,26 @@
+// Copyright (c) 2011-2016 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#define BOOST_TEST_MODULE Bitcoin Test Suite
+
+#include "net.h"
+
+#include <boost/test/unit_test.hpp>
+
+std::unique_ptr<CConnman> g_connman;
+
+[[noreturn]] void Shutdown(void* parg)
+{
+ std::exit(EXIT_SUCCESS);
+}
+
+[[noreturn]] void StartShutdown()
+{
+ std::exit(EXIT_SUCCESS);
+}
+
+bool ShutdownRequested()
+{
+ return false;
+}
diff --git a/src/test/test_random.h b/src/test/test_random.h
deleted file mode 100644
index 4a1637ac72..0000000000
--- a/src/test/test_random.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2016 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#ifndef BITCOIN_TEST_RANDOM_H
-#define BITCOIN_TEST_RANDOM_H
-
-#include "random.h"
-
-extern FastRandomContext insecure_rand_ctx;
-
-static inline void seed_insecure_rand(bool fDeterministic = false)
-{
- insecure_rand_ctx = FastRandomContext(fDeterministic);
-}
-
-static inline uint32_t insecure_rand(void)
-{
- return insecure_rand_ctx.rand32();
-}
-
-#endif
diff --git a/src/test/testutil.cpp b/src/test/testutil.cpp
deleted file mode 100644
index 304cffb798..0000000000
--- a/src/test/testutil.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) 2009-2016 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include "testutil.h"
-
-#ifdef WIN32
-#include <shlobj.h>
-#endif
-
-#include <boost/filesystem.hpp>
-
-boost::filesystem::path GetTempPath() {
-#if BOOST_FILESYSTEM_VERSION == 3
- return boost::filesystem::temp_directory_path();
-#else
- // TODO: remove when we don't support filesystem v2 anymore
- boost::filesystem::path path;
-#ifdef WIN32
- char pszPath[MAX_PATH] = "";
-
- if (GetTempPathA(MAX_PATH, pszPath))
- path = boost::filesystem::path(pszPath);
-#else
- path = boost::filesystem::path("/tmp");
-#endif
- if (path.empty() || !boost::filesystem::is_directory(path)) {
- LogPrintf("GetTempPath(): failed to find temp path\n");
- return boost::filesystem::path("");
- }
- return path;
-#endif
-}
diff --git a/src/test/testutil.h b/src/test/testutil.h
deleted file mode 100644
index 5875dc50e6..0000000000
--- a/src/test/testutil.h
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2009-2016 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-/**
- * Utility functions shared by unit tests
- */
-#ifndef BITCOIN_TEST_TESTUTIL_H
-#define BITCOIN_TEST_TESTUTIL_H
-
-#include <boost/filesystem/path.hpp>
-
-boost::filesystem::path GetTempPath();
-
-#endif // BITCOIN_TEST_TESTUTIL_H
diff --git a/src/test/torcontrol_tests.cpp b/src/test/torcontrol_tests.cpp
new file mode 100644
index 0000000000..b7affaacde
--- /dev/null
+++ b/src/test/torcontrol_tests.cpp
@@ -0,0 +1,199 @@
+// Copyright (c) 2017 The Zcash developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+//
+#include "test/test_bitcoin.h"
+#include "torcontrol.cpp"
+
+#include <boost/test/unit_test.hpp>
+
+
+BOOST_FIXTURE_TEST_SUITE(torcontrol_tests, BasicTestingSetup)
+
+void CheckSplitTorReplyLine(std::string input, std::string command, std::string args)
+{
+ BOOST_TEST_MESSAGE(std::string("CheckSplitTorReplyLine(") + input + ")");
+ auto ret = SplitTorReplyLine(input);
+ BOOST_CHECK_EQUAL(ret.first, command);
+ BOOST_CHECK_EQUAL(ret.second, args);
+}
+
+BOOST_AUTO_TEST_CASE(util_SplitTorReplyLine)
+{
+ // Data we should receive during normal usage
+ CheckSplitTorReplyLine(
+ "PROTOCOLINFO PIVERSION",
+ "PROTOCOLINFO", "PIVERSION");
+ CheckSplitTorReplyLine(
+ "AUTH METHODS=COOKIE,SAFECOOKIE COOKIEFILE=\"/home/x/.tor/control_auth_cookie\"",
+ "AUTH", "METHODS=COOKIE,SAFECOOKIE COOKIEFILE=\"/home/x/.tor/control_auth_cookie\"");
+ CheckSplitTorReplyLine(
+ "AUTH METHODS=NULL",
+ "AUTH", "METHODS=NULL");
+ CheckSplitTorReplyLine(
+ "AUTH METHODS=HASHEDPASSWORD",
+ "AUTH", "METHODS=HASHEDPASSWORD");
+ CheckSplitTorReplyLine(
+ "VERSION Tor=\"0.2.9.8 (git-a0df013ea241b026)\"",
+ "VERSION", "Tor=\"0.2.9.8 (git-a0df013ea241b026)\"");
+ CheckSplitTorReplyLine(
+ "AUTHCHALLENGE SERVERHASH=aaaa SERVERNONCE=bbbb",
+ "AUTHCHALLENGE", "SERVERHASH=aaaa SERVERNONCE=bbbb");
+
+ // Other valid inputs
+ CheckSplitTorReplyLine("COMMAND", "COMMAND", "");
+ CheckSplitTorReplyLine("COMMAND SOME ARGS", "COMMAND", "SOME ARGS");
+
+ // These inputs are valid because PROTOCOLINFO accepts an OtherLine that is
+ // just an OptArguments, which enables multiple spaces to be present
+ // between the command and arguments.
+ CheckSplitTorReplyLine("COMMAND ARGS", "COMMAND", " ARGS");
+ CheckSplitTorReplyLine("COMMAND EVEN+more ARGS", "COMMAND", " EVEN+more ARGS");
+}
+
+void CheckParseTorReplyMapping(std::string input, std::map<std::string,std::string> expected)
+{
+ BOOST_TEST_MESSAGE(std::string("CheckParseTorReplyMapping(") + input + ")");
+ auto ret = ParseTorReplyMapping(input);
+ BOOST_CHECK_EQUAL(ret.size(), expected.size());
+ auto r_it = ret.begin();
+ auto e_it = expected.begin();
+ while (r_it != ret.end() && e_it != expected.end()) {
+ BOOST_CHECK_EQUAL(r_it->first, e_it->first);
+ BOOST_CHECK_EQUAL(r_it->second, e_it->second);
+ r_it++;
+ e_it++;
+ }
+}
+
+BOOST_AUTO_TEST_CASE(util_ParseTorReplyMapping)
+{
+ // Data we should receive during normal usage
+ CheckParseTorReplyMapping(
+ "METHODS=COOKIE,SAFECOOKIE COOKIEFILE=\"/home/x/.tor/control_auth_cookie\"", {
+ {"METHODS", "COOKIE,SAFECOOKIE"},
+ {"COOKIEFILE", "/home/x/.tor/control_auth_cookie"},
+ });
+ CheckParseTorReplyMapping(
+ "METHODS=NULL", {
+ {"METHODS", "NULL"},
+ });
+ CheckParseTorReplyMapping(
+ "METHODS=HASHEDPASSWORD", {
+ {"METHODS", "HASHEDPASSWORD"},
+ });
+ CheckParseTorReplyMapping(
+ "Tor=\"0.2.9.8 (git-a0df013ea241b026)\"", {
+ {"Tor", "0.2.9.8 (git-a0df013ea241b026)"},
+ });
+ CheckParseTorReplyMapping(
+ "SERVERHASH=aaaa SERVERNONCE=bbbb", {
+ {"SERVERHASH", "aaaa"},
+ {"SERVERNONCE", "bbbb"},
+ });
+ CheckParseTorReplyMapping(
+ "ServiceID=exampleonion1234", {
+ {"ServiceID", "exampleonion1234"},
+ });
+ CheckParseTorReplyMapping(
+ "PrivateKey=RSA1024:BLOB", {
+ {"PrivateKey", "RSA1024:BLOB"},
+ });
+ CheckParseTorReplyMapping(
+ "ClientAuth=bob:BLOB", {
+ {"ClientAuth", "bob:BLOB"},
+ });
+
+ // Other valid inputs
+ CheckParseTorReplyMapping(
+ "Foo=Bar=Baz Spam=Eggs", {
+ {"Foo", "Bar=Baz"},
+ {"Spam", "Eggs"},
+ });
+ CheckParseTorReplyMapping(
+ "Foo=\"Bar=Baz\"", {
+ {"Foo", "Bar=Baz"},
+ });
+ CheckParseTorReplyMapping(
+ "Foo=\"Bar Baz\"", {
+ {"Foo", "Bar Baz"},
+ });
+
+ // Escapes
+ CheckParseTorReplyMapping(
+ "Foo=\"Bar\\ Baz\"", {
+ {"Foo", "Bar Baz"},
+ });
+ CheckParseTorReplyMapping(
+ "Foo=\"Bar\\Baz\"", {
+ {"Foo", "BarBaz"},
+ });
+ CheckParseTorReplyMapping(
+ "Foo=\"Bar\\@Baz\"", {
+ {"Foo", "Bar@Baz"},
+ });
+ CheckParseTorReplyMapping(
+ "Foo=\"Bar\\\"Baz\" Spam=\"\\\"Eggs\\\"\"", {
+ {"Foo", "Bar\"Baz"},
+ {"Spam", "\"Eggs\""},
+ });
+ CheckParseTorReplyMapping(
+ "Foo=\"Bar\\\\Baz\"", {
+ {"Foo", "Bar\\Baz"},
+ });
+
+ // C escapes
+ CheckParseTorReplyMapping(
+ "Foo=\"Bar\\nBaz\\t\" Spam=\"\\rEggs\" Octals=\"\\1a\\11\\17\\18\\81\\377\\378\\400\\2222\" Final=Check", {
+ {"Foo", "Bar\nBaz\t"},
+ {"Spam", "\rEggs"},
+ {"Octals", "\1a\11\17\1" "881\377\37" "8\40" "0\222" "2"},
+ {"Final", "Check"},
+ });
+ CheckParseTorReplyMapping(
+ "Valid=Mapping Escaped=\"Escape\\\\\"", {
+ {"Valid", "Mapping"},
+ {"Escaped", "Escape\\"},
+ });
+ CheckParseTorReplyMapping(
+ "Valid=Mapping Bare=\"Escape\\\"", {});
+ CheckParseTorReplyMapping(
+ "OneOctal=\"OneEnd\\1\" TwoOctal=\"TwoEnd\\11\"", {
+ {"OneOctal", "OneEnd\1"},
+ {"TwoOctal", "TwoEnd\11"},
+ });
+
+ // Special handling for null case
+ // (needed because string comparison reads the null as end-of-string)
+ BOOST_TEST_MESSAGE(std::string("CheckParseTorReplyMapping(Null=\"\\0\")"));
+ auto ret = ParseTorReplyMapping("Null=\"\\0\"");
+ BOOST_CHECK_EQUAL(ret.size(), 1);
+ auto r_it = ret.begin();
+ BOOST_CHECK_EQUAL(r_it->first, "Null");
+ BOOST_CHECK_EQUAL(r_it->second.size(), 1);
+ BOOST_CHECK_EQUAL(r_it->second[0], '\0');
+
+ // A more complex valid grammar. PROTOCOLINFO accepts a VersionLine that
+ // takes a key=value pair followed by an OptArguments, making this valid.
+ // Because an OptArguments contains no semantic data, there is no point in
+ // parsing it.
+ CheckParseTorReplyMapping(
+ "SOME=args,here MORE optional=arguments here", {
+ {"SOME", "args,here"},
+ });
+
+ // Inputs that are effectively invalid under the target grammar.
+ // PROTOCOLINFO accepts an OtherLine that is just an OptArguments, which
+ // would make these inputs valid. However,
+ // - This parser is never used in that situation, because the
+ // SplitTorReplyLine parser enables OtherLine to be skipped.
+ // - Even if these were valid, an OptArguments contains no semantic data,
+ // so there is no point in parsing it.
+ CheckParseTorReplyMapping("ARGS", {});
+ CheckParseTorReplyMapping("MORE ARGS", {});
+ CheckParseTorReplyMapping("MORE ARGS", {});
+ CheckParseTorReplyMapping("EVEN more=ARGS", {});
+ CheckParseTorReplyMapping("EVEN+more ARGS", {});
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 374423179c..cb6ab7cdbe 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -8,11 +8,12 @@
#include "clientversion.h"
#include "checkqueue.h"
+#include "consensus/tx_verify.h"
#include "consensus/validation.h"
#include "core_io.h"
#include "key.h"
#include "keystore.h"
-#include "validation.h" // For CheckTransaction
+#include "validation.h"
#include "policy/policy.h"
#include "script/script.h"
#include "script/sign.h"
@@ -25,10 +26,7 @@
#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 <boost/foreach.hpp>
#include <univalue.h>
@@ -37,24 +35,25 @@ typedef std::vector<unsigned char> valtype;
// In script_tests.cpp
extern UniValue read_json(const std::string& jsondata);
-static std::map<std::string, unsigned int> mapFlagNames = boost::assign::map_list_of
- (std::string("NONE"), (unsigned int)SCRIPT_VERIFY_NONE)
- (std::string("P2SH"), (unsigned int)SCRIPT_VERIFY_P2SH)
- (std::string("STRICTENC"), (unsigned int)SCRIPT_VERIFY_STRICTENC)
- (std::string("DERSIG"), (unsigned int)SCRIPT_VERIFY_DERSIG)
- (std::string("LOW_S"), (unsigned int)SCRIPT_VERIFY_LOW_S)
- (std::string("SIGPUSHONLY"), (unsigned int)SCRIPT_VERIFY_SIGPUSHONLY)
- (std::string("MINIMALDATA"), (unsigned int)SCRIPT_VERIFY_MINIMALDATA)
- (std::string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY)
- (std::string("DISCOURAGE_UPGRADABLE_NOPS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
- (std::string("CLEANSTACK"), (unsigned int)SCRIPT_VERIFY_CLEANSTACK)
- (std::string("MINIMALIF"), (unsigned int)SCRIPT_VERIFY_MINIMALIF)
- (std::string("NULLFAIL"), (unsigned int)SCRIPT_VERIFY_NULLFAIL)
- (std::string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)
- (std::string("CHECKSEQUENCEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)
- (std::string("WITNESS"), (unsigned int)SCRIPT_VERIFY_WITNESS)
- (std::string("DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM)
- (std::string("WITNESS_PUBKEYTYPE"), (unsigned int)SCRIPT_VERIFY_WITNESS_PUBKEYTYPE);
+static std::map<std::string, unsigned int> mapFlagNames = {
+ {std::string("NONE"), (unsigned int)SCRIPT_VERIFY_NONE},
+ {std::string("P2SH"), (unsigned int)SCRIPT_VERIFY_P2SH},
+ {std::string("STRICTENC"), (unsigned int)SCRIPT_VERIFY_STRICTENC},
+ {std::string("DERSIG"), (unsigned int)SCRIPT_VERIFY_DERSIG},
+ {std::string("LOW_S"), (unsigned int)SCRIPT_VERIFY_LOW_S},
+ {std::string("SIGPUSHONLY"), (unsigned int)SCRIPT_VERIFY_SIGPUSHONLY},
+ {std::string("MINIMALDATA"), (unsigned int)SCRIPT_VERIFY_MINIMALDATA},
+ {std::string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY},
+ {std::string("DISCOURAGE_UPGRADABLE_NOPS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS},
+ {std::string("CLEANSTACK"), (unsigned int)SCRIPT_VERIFY_CLEANSTACK},
+ {std::string("MINIMALIF"), (unsigned int)SCRIPT_VERIFY_MINIMALIF},
+ {std::string("NULLFAIL"), (unsigned int)SCRIPT_VERIFY_NULLFAIL},
+ {std::string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY},
+ {std::string("CHECKSEQUENCEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY},
+ {std::string("WITNESS"), (unsigned int)SCRIPT_VERIFY_WITNESS},
+ {std::string("DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM},
+ {std::string("WITNESS_PUBKEYTYPE"), (unsigned int)SCRIPT_VERIFY_WITNESS_PUBKEYTYPE},
+};
unsigned int ParseScriptFlags(std::string strFlags)
{
@@ -65,7 +64,7 @@ unsigned int ParseScriptFlags(std::string strFlags)
std::vector<std::string> words;
boost::algorithm::split(words, strFlags, boost::algorithm::is_any_of(","));
- BOOST_FOREACH(std::string word, words)
+ for (std::string word : words)
{
if (!mapFlagNames.count(word))
BOOST_ERROR("Bad test: unknown verification flag '" << word << "'");
@@ -189,7 +188,9 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
// verifyFlags is a comma separated list of script verification flags to apply, or "NONE"
UniValue tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid)));
- ScriptError err;
+ // Initialize to SCRIPT_ERR_OK. The tests expect err to be changed to a
+ // value other than SCRIPT_ERR_OK.
+ ScriptError err = SCRIPT_ERR_OK;
for (unsigned int idx = 0; idx < tests.size(); idx++) {
UniValue test = tests[idx];
std::string strTest = test.write();
@@ -304,14 +305,14 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
dummyTransactions[0].vout[0].scriptPubKey << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG;
dummyTransactions[0].vout[1].nValue = 50*CENT;
dummyTransactions[0].vout[1].scriptPubKey << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG;
- coinsRet.ModifyCoins(dummyTransactions[0].GetHash())->FromTx(dummyTransactions[0], 0);
+ AddCoins(coinsRet, dummyTransactions[0], 0);
dummyTransactions[1].vout.resize(2);
dummyTransactions[1].vout[0].nValue = 21*CENT;
dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID());
dummyTransactions[1].vout[1].nValue = 22*CENT;
dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID());
- coinsRet.ModifyCoins(dummyTransactions[1].GetHash())->FromTx(dummyTransactions[1], 0);
+ AddCoins(coinsRet, dummyTransactions[1], 0);
return dummyTransactions;
}
@@ -391,7 +392,7 @@ void CheckWithFlag(const CTransactionRef& output, const CMutableTransaction& inp
static CScript PushAll(const std::vector<valtype>& values)
{
CScript result;
- BOOST_FOREACH(const valtype& v, values) {
+ for (const valtype& v : values) {
if (v.size() == 0) {
result << OP_0;
} else if (v.size() == 1 && v[0] >= 1 && v[0] <= 16) {
@@ -467,19 +468,19 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction) {
for (int i=0; i<20; i++)
threadGroup.create_thread(boost::bind(&CCheckQueue<CScriptCheck>::Thread, boost::ref(scriptcheckqueue)));
- CCoins coins;
- coins.nVersion = 1;
- coins.fCoinBase = false;
+ std::vector<Coin> coins;
for(uint32_t i = 0; i < mtx.vin.size(); i++) {
- CTxOut txout;
- txout.nValue = 1000;
- txout.scriptPubKey = scriptPubKey;
- coins.vout.push_back(txout);
+ Coin coin;
+ coin.nHeight = 1;
+ coin.fCoinBase = false;
+ coin.out.nValue = 1000;
+ coin.out.scriptPubKey = scriptPubKey;
+ coins.emplace_back(std::move(coin));
}
for(uint32_t i = 0; i < mtx.vin.size(); i++) {
std::vector<CScriptCheck> vChecks;
- CScriptCheck check(coins, tx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false, &txdata);
+ CScriptCheck check(coins[tx.vin[i].prevout.n].out, tx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false, &txdata);
vChecks.push_back(CScriptCheck());
check.swap(vChecks.back());
control.Add(vChecks);
@@ -690,7 +691,7 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
BOOST_CHECK(IsStandardTx(t, reason));
// Check dust with default relay fee:
- CAmount nDustThreshold = 182 * dustRelayFee.GetFeePerK()/1000 * 3;
+ CAmount nDustThreshold = 182 * dustRelayFee.GetFeePerK()/1000;
BOOST_CHECK_EQUAL(nDustThreshold, 546);
// dust:
t.vout[0].nValue = nDustThreshold - 1;
@@ -700,13 +701,13 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
BOOST_CHECK(IsStandardTx(t, reason));
// Check dust with odd relay fee to verify rounding:
- // nDustThreshold = 182 * 1234 / 1000 * 3
- dustRelayFee = CFeeRate(1234);
+ // nDustThreshold = 182 * 3702 / 1000
+ dustRelayFee = CFeeRate(3702);
// dust:
- t.vout[0].nValue = 672 - 1;
+ t.vout[0].nValue = 673 - 1;
BOOST_CHECK(!IsStandardTx(t, reason));
// not dust:
- t.vout[0].nValue = 672;
+ t.vout[0].nValue = 673;
BOOST_CHECK(IsStandardTx(t, reason));
dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE);
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index acccaee98c..82ca93e7da 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -10,11 +10,17 @@
#include "txmempool.h"
#include "random.h"
#include "script/standard.h"
+#include "script/sign.h"
#include "test/test_bitcoin.h"
#include "utiltime.h"
+#include "core_io.h"
+#include "keystore.h"
+#include "policy/policy.h"
#include <boost/test/unit_test.hpp>
+bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks);
+
BOOST_AUTO_TEST_SUITE(tx_validationcache_tests)
static bool
@@ -23,7 +29,8 @@ ToMemPool(CMutableTransaction& tx)
LOCK(cs_main);
CValidationState state;
- return AcceptToMemoryPool(mempool, state, MakeTransactionRef(tx), false, NULL, true, 0);
+ return AcceptToMemoryPool(mempool, state, MakeTransactionRef(tx), nullptr /* pfMissingInputs */,
+ nullptr /* plTxnReplaced */, true /* bypass_limits */, 0 /* nAbsurdFee */);
}
BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
@@ -84,4 +91,282 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
BOOST_CHECK_EQUAL(mempool.size(), 0);
}
+// Run CheckInputs (using pcoinsTip) on the given transaction, for all script
+// flags. Test that CheckInputs passes for all flags that don't overlap with
+// the failing_flags argument, but otherwise fails.
+// CHECKLOCKTIMEVERIFY and CHECKSEQUENCEVERIFY (and future NOP codes that may
+// get reassigned) have an interaction with DISCOURAGE_UPGRADABLE_NOPS: if
+// the script flags used contain DISCOURAGE_UPGRADABLE_NOPS but don't contain
+// CHECKLOCKTIMEVERIFY (or CHECKSEQUENCEVERIFY), but the script does contain
+// OP_CHECKLOCKTIMEVERIFY (or OP_CHECKSEQUENCEVERIFY), then script execution
+// should fail.
+// Capture this interaction with the upgraded_nop argument: set it when evaluating
+// any script flag that is implemented as an upgraded NOP code.
+void ValidateCheckInputsForAllFlags(CMutableTransaction &tx, uint32_t failing_flags, bool add_to_cache, bool upgraded_nop)
+{
+ PrecomputedTransactionData txdata(tx);
+ // If we add many more flags, this loop can get too expensive, but we can
+ // rewrite in the future to randomly pick a set of flags to evaluate.
+ for (uint32_t test_flags=0; test_flags < (1U << 16); test_flags += 1) {
+ CValidationState state;
+ // Filter out incompatible flag choices
+ if ((test_flags & SCRIPT_VERIFY_CLEANSTACK)) {
+ // CLEANSTACK requires P2SH and WITNESS, see VerifyScript() in
+ // script/interpreter.cpp
+ test_flags |= SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS;
+ }
+ if ((test_flags & SCRIPT_VERIFY_WITNESS)) {
+ // WITNESS requires P2SH
+ test_flags |= SCRIPT_VERIFY_P2SH;
+ }
+ bool ret = CheckInputs(tx, state, pcoinsTip, true, test_flags, true, add_to_cache, txdata, nullptr);
+ // CheckInputs should succeed iff test_flags doesn't intersect with
+ // failing_flags
+ bool expected_return_value = !(test_flags & failing_flags);
+ if (expected_return_value && upgraded_nop) {
+ // If the script flag being tested corresponds to an upgraded NOP,
+ // then script execution should fail if DISCOURAGE_UPGRADABLE_NOPS
+ // is set.
+ expected_return_value = !(test_flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS);
+ }
+ BOOST_CHECK_EQUAL(ret, expected_return_value);
+
+ // Test the caching
+ if (ret && add_to_cache) {
+ // Check that we get a cache hit if the tx was valid
+ std::vector<CScriptCheck> scriptchecks;
+ BOOST_CHECK(CheckInputs(tx, state, pcoinsTip, true, test_flags, true, add_to_cache, txdata, &scriptchecks));
+ BOOST_CHECK(scriptchecks.empty());
+ } else {
+ // Check that we get script executions to check, if the transaction
+ // was invalid, or we didn't add to cache.
+ std::vector<CScriptCheck> scriptchecks;
+ BOOST_CHECK(CheckInputs(tx, state, pcoinsTip, true, test_flags, true, add_to_cache, txdata, &scriptchecks));
+ BOOST_CHECK_EQUAL(scriptchecks.size(), tx.vin.size());
+ }
+ }
+}
+
+BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
+{
+ // Test that passing CheckInputs with one set of script flags doesn't imply
+ // that we would pass again with a different set of flags.
+ InitScriptExecutionCache();
+
+ CScript p2pk_scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
+ CScript p2sh_scriptPubKey = GetScriptForDestination(CScriptID(p2pk_scriptPubKey));
+ CScript p2pkh_scriptPubKey = GetScriptForDestination(coinbaseKey.GetPubKey().GetID());
+ CScript p2wpkh_scriptPubKey = GetScriptForWitness(p2pkh_scriptPubKey);
+
+ CBasicKeyStore keystore;
+ keystore.AddKey(coinbaseKey);
+ keystore.AddCScript(p2pk_scriptPubKey);
+
+ // flags to test: SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, SCRIPT_VERIFY_CHECKSEQUENCE_VERIFY, SCRIPT_VERIFY_NULLDUMMY, uncompressed pubkey thing
+
+ // Create 2 outputs that match the three scripts above, spending the first
+ // coinbase tx.
+ CMutableTransaction spend_tx;
+
+ spend_tx.nVersion = 1;
+ spend_tx.vin.resize(1);
+ spend_tx.vin[0].prevout.hash = coinbaseTxns[0].GetHash();
+ spend_tx.vin[0].prevout.n = 0;
+ spend_tx.vout.resize(4);
+ spend_tx.vout[0].nValue = 11*CENT;
+ spend_tx.vout[0].scriptPubKey = p2sh_scriptPubKey;
+ spend_tx.vout[1].nValue = 11*CENT;
+ spend_tx.vout[1].scriptPubKey = p2wpkh_scriptPubKey;
+ spend_tx.vout[2].nValue = 11*CENT;
+ spend_tx.vout[2].scriptPubKey = CScript() << OP_CHECKLOCKTIMEVERIFY << OP_DROP << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
+ spend_tx.vout[3].nValue = 11*CENT;
+ spend_tx.vout[3].scriptPubKey = CScript() << OP_CHECKSEQUENCEVERIFY << OP_DROP << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
+
+ // Sign, with a non-DER signature
+ {
+ std::vector<unsigned char> vchSig;
+ uint256 hash = SignatureHash(p2pk_scriptPubKey, spend_tx, 0, SIGHASH_ALL, 0, SIGVERSION_BASE);
+ BOOST_CHECK(coinbaseKey.Sign(hash, vchSig));
+ vchSig.push_back((unsigned char) 0); // padding byte makes this non-DER
+ vchSig.push_back((unsigned char)SIGHASH_ALL);
+ spend_tx.vin[0].scriptSig << vchSig;
+ }
+
+ LOCK(cs_main);
+
+ // Test that invalidity under a set of flags doesn't preclude validity
+ // under other (eg consensus) flags.
+ // spend_tx is invalid according to DERSIG
+ {
+ CValidationState state;
+ PrecomputedTransactionData ptd_spend_tx(spend_tx);
+
+ BOOST_CHECK(!CheckInputs(spend_tx, state, pcoinsTip, true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr));
+
+ // If we call again asking for scriptchecks (as happens in
+ // ConnectBlock), we should add a script check object for this -- we're
+ // not caching invalidity (if that changes, delete this test case).
+ std::vector<CScriptCheck> scriptchecks;
+ BOOST_CHECK(CheckInputs(spend_tx, state, pcoinsTip, true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, &scriptchecks));
+ BOOST_CHECK_EQUAL(scriptchecks.size(), 1);
+
+ // Test that CheckInputs returns true iff DERSIG-enforcing flags are
+ // not present. Don't add these checks to the cache, so that we can
+ // test later that block validation works fine in the absence of cached
+ // successes.
+ ValidateCheckInputsForAllFlags(spend_tx, SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC, false, false);
+
+ // And if we produce a block with this tx, it should be valid (DERSIG not
+ // enabled yet), even though there's no cache entry.
+ CBlock block;
+
+ block = CreateAndProcessBlock({spend_tx}, p2pk_scriptPubKey);
+ BOOST_CHECK(chainActive.Tip()->GetBlockHash() == block.GetHash());
+ BOOST_CHECK(pcoinsTip->GetBestBlock() == block.GetHash());
+ }
+
+ // Test P2SH: construct a transaction that is valid without P2SH, and
+ // then test validity with P2SH.
+ {
+ CMutableTransaction invalid_under_p2sh_tx;
+ invalid_under_p2sh_tx.nVersion = 1;
+ invalid_under_p2sh_tx.vin.resize(1);
+ invalid_under_p2sh_tx.vin[0].prevout.hash = spend_tx.GetHash();
+ invalid_under_p2sh_tx.vin[0].prevout.n = 0;
+ invalid_under_p2sh_tx.vout.resize(1);
+ invalid_under_p2sh_tx.vout[0].nValue = 11*CENT;
+ invalid_under_p2sh_tx.vout[0].scriptPubKey = p2pk_scriptPubKey;
+ std::vector<unsigned char> vchSig2(p2pk_scriptPubKey.begin(), p2pk_scriptPubKey.end());
+ invalid_under_p2sh_tx.vin[0].scriptSig << vchSig2;
+
+ ValidateCheckInputsForAllFlags(invalid_under_p2sh_tx, SCRIPT_VERIFY_P2SH, true, false);
+ }
+
+ // Test CHECKLOCKTIMEVERIFY
+ {
+ CMutableTransaction invalid_with_cltv_tx;
+ invalid_with_cltv_tx.nVersion = 1;
+ invalid_with_cltv_tx.nLockTime = 100;
+ invalid_with_cltv_tx.vin.resize(1);
+ invalid_with_cltv_tx.vin[0].prevout.hash = spend_tx.GetHash();
+ invalid_with_cltv_tx.vin[0].prevout.n = 2;
+ invalid_with_cltv_tx.vin[0].nSequence = 0;
+ invalid_with_cltv_tx.vout.resize(1);
+ invalid_with_cltv_tx.vout[0].nValue = 11*CENT;
+ invalid_with_cltv_tx.vout[0].scriptPubKey = p2pk_scriptPubKey;
+
+ // Sign
+ std::vector<unsigned char> vchSig;
+ uint256 hash = SignatureHash(spend_tx.vout[2].scriptPubKey, invalid_with_cltv_tx, 0, SIGHASH_ALL, 0, SIGVERSION_BASE);
+ BOOST_CHECK(coinbaseKey.Sign(hash, vchSig));
+ vchSig.push_back((unsigned char)SIGHASH_ALL);
+ invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 101;
+
+ ValidateCheckInputsForAllFlags(invalid_with_cltv_tx, SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true);
+
+ // Make it valid, and check again
+ invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
+ CValidationState state;
+ PrecomputedTransactionData txdata(invalid_with_cltv_tx);
+ BOOST_CHECK(CheckInputs(invalid_with_cltv_tx, state, pcoinsTip, true, SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr));
+ }
+
+ // TEST CHECKSEQUENCEVERIFY
+ {
+ CMutableTransaction invalid_with_csv_tx;
+ invalid_with_csv_tx.nVersion = 2;
+ invalid_with_csv_tx.vin.resize(1);
+ invalid_with_csv_tx.vin[0].prevout.hash = spend_tx.GetHash();
+ invalid_with_csv_tx.vin[0].prevout.n = 3;
+ invalid_with_csv_tx.vin[0].nSequence = 100;
+ invalid_with_csv_tx.vout.resize(1);
+ invalid_with_csv_tx.vout[0].nValue = 11*CENT;
+ invalid_with_csv_tx.vout[0].scriptPubKey = p2pk_scriptPubKey;
+
+ // Sign
+ std::vector<unsigned char> vchSig;
+ uint256 hash = SignatureHash(spend_tx.vout[3].scriptPubKey, invalid_with_csv_tx, 0, SIGHASH_ALL, 0, SIGVERSION_BASE);
+ BOOST_CHECK(coinbaseKey.Sign(hash, vchSig));
+ vchSig.push_back((unsigned char)SIGHASH_ALL);
+ invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 101;
+
+ ValidateCheckInputsForAllFlags(invalid_with_csv_tx, SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true);
+
+ // Make it valid, and check again
+ invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
+ CValidationState state;
+ PrecomputedTransactionData txdata(invalid_with_csv_tx);
+ BOOST_CHECK(CheckInputs(invalid_with_csv_tx, state, pcoinsTip, true, SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr));
+ }
+
+ // TODO: add tests for remaining script flags
+
+ // Test that passing CheckInputs with a valid witness doesn't imply success
+ // for the same tx with a different witness.
+ {
+ CMutableTransaction valid_with_witness_tx;
+ valid_with_witness_tx.nVersion = 1;
+ valid_with_witness_tx.vin.resize(1);
+ valid_with_witness_tx.vin[0].prevout.hash = spend_tx.GetHash();
+ valid_with_witness_tx.vin[0].prevout.n = 1;
+ valid_with_witness_tx.vout.resize(1);
+ valid_with_witness_tx.vout[0].nValue = 11*CENT;
+ valid_with_witness_tx.vout[0].scriptPubKey = p2pk_scriptPubKey;
+
+ // Sign
+ SignatureData sigdata;
+ ProduceSignature(MutableTransactionSignatureCreator(&keystore, &valid_with_witness_tx, 0, 11*CENT, SIGHASH_ALL), spend_tx.vout[1].scriptPubKey, sigdata);
+ UpdateTransaction(valid_with_witness_tx, 0, sigdata);
+
+ // This should be valid under all script flags.
+ ValidateCheckInputsForAllFlags(valid_with_witness_tx, 0, true, false);
+
+ // Remove the witness, and check that it is now invalid.
+ valid_with_witness_tx.vin[0].scriptWitness.SetNull();
+ ValidateCheckInputsForAllFlags(valid_with_witness_tx, SCRIPT_VERIFY_WITNESS, true, false);
+ }
+
+ {
+ // Test a transaction with multiple inputs.
+ CMutableTransaction tx;
+
+ tx.nVersion = 1;
+ tx.vin.resize(2);
+ tx.vin[0].prevout.hash = spend_tx.GetHash();
+ tx.vin[0].prevout.n = 0;
+ tx.vin[1].prevout.hash = spend_tx.GetHash();
+ tx.vin[1].prevout.n = 1;
+ tx.vout.resize(1);
+ tx.vout[0].nValue = 22*CENT;
+ tx.vout[0].scriptPubKey = p2pk_scriptPubKey;
+
+ // Sign
+ for (int i=0; i<2; ++i) {
+ SignatureData sigdata;
+ ProduceSignature(MutableTransactionSignatureCreator(&keystore, &tx, i, 11*CENT, SIGHASH_ALL), spend_tx.vout[i].scriptPubKey, sigdata);
+ UpdateTransaction(tx, i, sigdata);
+ }
+
+ // This should be valid under all script flags
+ ValidateCheckInputsForAllFlags(tx, 0, true, false);
+
+ // Check that if the second input is invalid, but the first input is
+ // valid, the transaction is not cached.
+ // Invalidate vin[1]
+ tx.vin[1].scriptWitness.SetNull();
+
+ CValidationState state;
+ PrecomputedTransactionData txdata(tx);
+ // This transaction is now invalid under segwit, because of the second input.
+ BOOST_CHECK(!CheckInputs(tx, state, pcoinsTip, true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, nullptr));
+
+ std::vector<CScriptCheck> scriptchecks;
+ // Make sure this transaction was not cached (ie because the first
+ // input was valid)
+ BOOST_CHECK(CheckInputs(tx, state, pcoinsTip, true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, &scriptchecks));
+ // Should get 2 script checks back -- caching is on a whole-transaction basis.
+ BOOST_CHECK_EQUAL(scriptchecks.size(), 2);
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 641655621c..6ec544290d 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -10,15 +10,12 @@
#include "utilstrencodings.h"
#include "utilmoneystr.h"
#include "test/test_bitcoin.h"
-#include "test/test_random.h"
#include <stdint.h>
#include <vector>
#include <boost/test/unit_test.hpp>
-extern std::map<std::string, std::string> mapArgs;
-
BOOST_FIXTURE_TEST_SUITE(util_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(util_criticalsection)
@@ -100,52 +97,67 @@ BOOST_AUTO_TEST_CASE(util_DateTimeStrFormat)
BOOST_CHECK_EQUAL(DateTimeStrFormat("%a, %d %b %Y %H:%M:%S +0000", 1317425777), "Fri, 30 Sep 2011 23:36:17 +0000");
}
+class TestArgsManager : public ArgsManager
+{
+public:
+ std::map<std::string, std::string>& GetMapArgs()
+ {
+ return mapArgs;
+ };
+ const std::map<std::string, std::vector<std::string> >& GetMapMultiArgs()
+ {
+ return mapMultiArgs;
+ };
+};
+
BOOST_AUTO_TEST_CASE(util_ParseParameters)
{
+ TestArgsManager testArgs;
const char *argv_test[] = {"-ignored", "-a", "-b", "-ccc=argument", "-ccc=multiple", "f", "-d=e"};
- ParseParameters(0, (char**)argv_test);
- BOOST_CHECK(mapArgs.empty() && mapMultiArgs.empty());
+ testArgs.ParseParameters(0, (char**)argv_test);
+ BOOST_CHECK(testArgs.GetMapArgs().empty() && testArgs.GetMapMultiArgs().empty());
- ParseParameters(1, (char**)argv_test);
- BOOST_CHECK(mapArgs.empty() && mapMultiArgs.empty());
+ testArgs.ParseParameters(1, (char**)argv_test);
+ BOOST_CHECK(testArgs.GetMapArgs().empty() && testArgs.GetMapMultiArgs().empty());
- ParseParameters(5, (char**)argv_test);
+ testArgs.ParseParameters(5, (char**)argv_test);
// expectation: -ignored is ignored (program name argument),
// -a, -b and -ccc end up in map, -d ignored because it is after
// a non-option argument (non-GNU option parsing)
- BOOST_CHECK(mapArgs.size() == 3 && mapMultiArgs.size() == 3);
- BOOST_CHECK(IsArgSet("-a") && IsArgSet("-b") && IsArgSet("-ccc")
- && !IsArgSet("f") && !IsArgSet("-d"));
- BOOST_CHECK(mapMultiArgs.count("-a") && mapMultiArgs.count("-b") && mapMultiArgs.count("-ccc")
- && !mapMultiArgs.count("f") && !mapMultiArgs.count("-d"));
-
- BOOST_CHECK(mapArgs["-a"] == "" && mapArgs["-ccc"] == "multiple");
- BOOST_CHECK(mapMultiArgs.at("-ccc").size() == 2);
+ BOOST_CHECK(testArgs.GetMapArgs().size() == 3 && testArgs.GetMapMultiArgs().size() == 3);
+ BOOST_CHECK(testArgs.IsArgSet("-a") && testArgs.IsArgSet("-b") && testArgs.IsArgSet("-ccc")
+ && !testArgs.IsArgSet("f") && !testArgs.IsArgSet("-d"));
+ BOOST_CHECK(testArgs.GetMapMultiArgs().count("-a") && testArgs.GetMapMultiArgs().count("-b") && testArgs.GetMapMultiArgs().count("-ccc")
+ && !testArgs.GetMapMultiArgs().count("f") && !testArgs.GetMapMultiArgs().count("-d"));
+
+ BOOST_CHECK(testArgs.GetMapArgs()["-a"] == "" && testArgs.GetMapArgs()["-ccc"] == "multiple");
+ BOOST_CHECK(testArgs.GetArgs("-ccc").size() == 2);
}
BOOST_AUTO_TEST_CASE(util_GetArg)
{
- mapArgs.clear();
- mapArgs["strtest1"] = "string...";
+ TestArgsManager testArgs;
+ testArgs.GetMapArgs().clear();
+ testArgs.GetMapArgs()["strtest1"] = "string...";
// strtest2 undefined on purpose
- mapArgs["inttest1"] = "12345";
- mapArgs["inttest2"] = "81985529216486895";
+ testArgs.GetMapArgs()["inttest1"] = "12345";
+ testArgs.GetMapArgs()["inttest2"] = "81985529216486895";
// inttest3 undefined on purpose
- mapArgs["booltest1"] = "";
+ testArgs.GetMapArgs()["booltest1"] = "";
// booltest2 undefined on purpose
- mapArgs["booltest3"] = "0";
- mapArgs["booltest4"] = "1";
-
- BOOST_CHECK_EQUAL(GetArg("strtest1", "default"), "string...");
- BOOST_CHECK_EQUAL(GetArg("strtest2", "default"), "default");
- BOOST_CHECK_EQUAL(GetArg("inttest1", -1), 12345);
- BOOST_CHECK_EQUAL(GetArg("inttest2", -1), 81985529216486895LL);
- BOOST_CHECK_EQUAL(GetArg("inttest3", -1), -1);
- BOOST_CHECK_EQUAL(GetBoolArg("booltest1", false), true);
- BOOST_CHECK_EQUAL(GetBoolArg("booltest2", false), false);
- BOOST_CHECK_EQUAL(GetBoolArg("booltest3", false), false);
- BOOST_CHECK_EQUAL(GetBoolArg("booltest4", false), true);
+ testArgs.GetMapArgs()["booltest3"] = "0";
+ testArgs.GetMapArgs()["booltest4"] = "1";
+
+ BOOST_CHECK_EQUAL(testArgs.GetArg("strtest1", "default"), "string...");
+ BOOST_CHECK_EQUAL(testArgs.GetArg("strtest2", "default"), "default");
+ BOOST_CHECK_EQUAL(testArgs.GetArg("inttest1", -1), 12345);
+ BOOST_CHECK_EQUAL(testArgs.GetArg("inttest2", -1), 81985529216486895LL);
+ BOOST_CHECK_EQUAL(testArgs.GetArg("inttest3", -1), -1);
+ BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest1", false), true);
+ BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest2", false), false);
+ BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest3", false), false);
+ BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest4", false), true);
}
BOOST_AUTO_TEST_CASE(util_FormatMoney)
@@ -241,13 +253,38 @@ BOOST_AUTO_TEST_CASE(util_IsHex)
BOOST_CHECK(!IsHex("0x0000"));
}
+BOOST_AUTO_TEST_CASE(util_IsHexNumber)
+{
+ BOOST_CHECK(IsHexNumber("0x0"));
+ BOOST_CHECK(IsHexNumber("0"));
+ BOOST_CHECK(IsHexNumber("0x10"));
+ BOOST_CHECK(IsHexNumber("10"));
+ BOOST_CHECK(IsHexNumber("0xff"));
+ BOOST_CHECK(IsHexNumber("ff"));
+ BOOST_CHECK(IsHexNumber("0xFfa"));
+ BOOST_CHECK(IsHexNumber("Ffa"));
+ BOOST_CHECK(IsHexNumber("0x00112233445566778899aabbccddeeffAABBCCDDEEFF"));
+ BOOST_CHECK(IsHexNumber("00112233445566778899aabbccddeeffAABBCCDDEEFF"));
+
+ BOOST_CHECK(!IsHexNumber("")); // empty string not allowed
+ BOOST_CHECK(!IsHexNumber("0x")); // empty string after prefix not allowed
+ BOOST_CHECK(!IsHexNumber("0x0 ")); // no spaces at end,
+ BOOST_CHECK(!IsHexNumber(" 0x0")); // or beginning,
+ BOOST_CHECK(!IsHexNumber("0x 0")); // or middle,
+ BOOST_CHECK(!IsHexNumber(" ")); // etc.
+ BOOST_CHECK(!IsHexNumber("0x0ga")); // invalid character
+ BOOST_CHECK(!IsHexNumber("x0")); // broken prefix
+ BOOST_CHECK(!IsHexNumber("0x0x00")); // two prefixes not allowed
+
+}
+
BOOST_AUTO_TEST_CASE(util_seed_insecure_rand)
{
- seed_insecure_rand(true);
+ SeedInsecureRand(true);
for (int mod=2;mod<11;mod++)
{
int mask = 1;
- // Really rough binomal confidence approximation.
+ // Really rough binomial confidence approximation.
int err = 30*10000./mod*sqrt((1./mod*(1-1./mod))/10000.);
//mask is 2^ceil(log2(mod))-1
while(mask<mod-1)mask=(mask<<1)+1;
@@ -257,7 +294,7 @@ BOOST_AUTO_TEST_CASE(util_seed_insecure_rand)
for (int i = 0; i < 10000; i++) {
uint32_t rval;
do{
- rval=insecure_rand()&mask;
+ rval=InsecureRand32()&mask;
}while(rval>=(uint32_t)mod);
count += rval==0;
}
@@ -316,12 +353,12 @@ BOOST_AUTO_TEST_CASE(test_ParseInt32)
{
int32_t n;
// Valid values
- BOOST_CHECK(ParseInt32("1234", NULL));
+ BOOST_CHECK(ParseInt32("1234", nullptr));
BOOST_CHECK(ParseInt32("0", &n) && n == 0);
BOOST_CHECK(ParseInt32("1234", &n) && n == 1234);
BOOST_CHECK(ParseInt32("01234", &n) && n == 1234); // no octal
BOOST_CHECK(ParseInt32("2147483647", &n) && n == 2147483647);
- BOOST_CHECK(ParseInt32("-2147483648", &n) && n == -2147483648);
+ BOOST_CHECK(ParseInt32("-2147483648", &n) && n == (-2147483647 - 1)); // (-2147483647 - 1) equals INT_MIN
BOOST_CHECK(ParseInt32("-1234", &n) && n == -1234);
// Invalid values
BOOST_CHECK(!ParseInt32("", &n));
@@ -335,17 +372,17 @@ BOOST_AUTO_TEST_CASE(test_ParseInt32)
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));
- BOOST_CHECK(!ParseInt32("-32482348723847471234", NULL));
- BOOST_CHECK(!ParseInt32("32482348723847471234", NULL));
+ BOOST_CHECK(!ParseInt32("-2147483649", nullptr));
+ BOOST_CHECK(!ParseInt32("2147483648", nullptr));
+ BOOST_CHECK(!ParseInt32("-32482348723847471234", nullptr));
+ BOOST_CHECK(!ParseInt32("32482348723847471234", nullptr));
}
BOOST_AUTO_TEST_CASE(test_ParseInt64)
{
int64_t n;
// Valid values
- BOOST_CHECK(ParseInt64("1234", NULL));
+ BOOST_CHECK(ParseInt64("1234", nullptr));
BOOST_CHECK(ParseInt64("0", &n) && n == 0LL);
BOOST_CHECK(ParseInt64("1234", &n) && n == 1234LL);
BOOST_CHECK(ParseInt64("01234", &n) && n == 1234LL); // no octal
@@ -365,17 +402,17 @@ BOOST_AUTO_TEST_CASE(test_ParseInt64)
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_CHECK(!ParseInt64("-9223372036854775809", nullptr));
+ BOOST_CHECK(!ParseInt64("9223372036854775808", nullptr));
+ BOOST_CHECK(!ParseInt64("-32482348723847471234", nullptr));
+ BOOST_CHECK(!ParseInt64("32482348723847471234", nullptr));
}
BOOST_AUTO_TEST_CASE(test_ParseUInt32)
{
uint32_t n;
// Valid values
- BOOST_CHECK(ParseUInt32("1234", NULL));
+ BOOST_CHECK(ParseUInt32("1234", nullptr));
BOOST_CHECK(ParseUInt32("0", &n) && n == 0);
BOOST_CHECK(ParseUInt32("1234", &n) && n == 1234);
BOOST_CHECK(ParseUInt32("01234", &n) && n == 1234); // no octal
@@ -398,15 +435,15 @@ BOOST_AUTO_TEST_CASE(test_ParseUInt32)
BOOST_CHECK(!ParseUInt32("-2147483648", &n));
BOOST_CHECK(!ParseUInt32("4294967296", &n));
BOOST_CHECK(!ParseUInt32("-1234", &n));
- BOOST_CHECK(!ParseUInt32("-32482348723847471234", NULL));
- BOOST_CHECK(!ParseUInt32("32482348723847471234", NULL));
+ BOOST_CHECK(!ParseUInt32("-32482348723847471234", nullptr));
+ BOOST_CHECK(!ParseUInt32("32482348723847471234", nullptr));
}
BOOST_AUTO_TEST_CASE(test_ParseUInt64)
{
uint64_t n;
// Valid values
- BOOST_CHECK(ParseUInt64("1234", NULL));
+ BOOST_CHECK(ParseUInt64("1234", nullptr));
BOOST_CHECK(ParseUInt64("0", &n) && n == 0LL);
BOOST_CHECK(ParseUInt64("1234", &n) && n == 1234LL);
BOOST_CHECK(ParseUInt64("01234", &n) && n == 1234LL); // no octal
@@ -426,9 +463,9 @@ BOOST_AUTO_TEST_CASE(test_ParseUInt64)
std::string teststr(test_bytes, sizeof(test_bytes));
BOOST_CHECK(!ParseUInt64(teststr, &n)); // no embedded NULs
// Overflow and underflow
- BOOST_CHECK(!ParseUInt64("-9223372036854775809", NULL));
- BOOST_CHECK(!ParseUInt64("18446744073709551616", NULL));
- BOOST_CHECK(!ParseUInt64("-32482348723847471234", NULL));
+ BOOST_CHECK(!ParseUInt64("-9223372036854775809", nullptr));
+ BOOST_CHECK(!ParseUInt64("18446744073709551616", nullptr));
+ BOOST_CHECK(!ParseUInt64("-32482348723847471234", nullptr));
BOOST_CHECK(!ParseUInt64("-2147483648", &n));
BOOST_CHECK(!ParseUInt64("-9223372036854775808", &n));
BOOST_CHECK(!ParseUInt64("-1234", &n));
@@ -438,7 +475,7 @@ BOOST_AUTO_TEST_CASE(test_ParseDouble)
{
double n;
// Valid values
- BOOST_CHECK(ParseDouble("1234", NULL));
+ BOOST_CHECK(ParseDouble("1234", nullptr));
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
@@ -458,8 +495,8 @@ BOOST_AUTO_TEST_CASE(test_ParseDouble)
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_CHECK(!ParseDouble("-1e10000", nullptr));
+ BOOST_CHECK(!ParseDouble("1e10000", nullptr));
}
BOOST_AUTO_TEST_CASE(test_FormatParagraph)
diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp
index bae0eff7e5..882afb2e20 100644
--- a/src/test/versionbits_tests.cpp
+++ b/src/test/versionbits_tests.cpp
@@ -5,7 +5,6 @@
#include "chain.h"
#include "versionbits.h"
#include "test/test_bitcoin.h"
-#include "test/test_random.h"
#include "chainparams.h"
#include "validation.h"
#include "consensus/params.h"
@@ -23,11 +22,11 @@ private:
mutable ThresholdConditionCache cache;
public:
- int64_t BeginTime(const Consensus::Params& params) const { return TestTime(10000); }
- int64_t EndTime(const Consensus::Params& params) const { return TestTime(20000); }
- int Period(const Consensus::Params& params) const { return 1000; }
- int Threshold(const Consensus::Params& params) const { return 900; }
- bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const { return (pindex->nVersion & 0x100); }
+ int64_t BeginTime(const Consensus::Params& params) const override { return TestTime(10000); }
+ int64_t EndTime(const Consensus::Params& params) const override { return TestTime(20000); }
+ int Period(const Consensus::Params& params) const override { return 1000; }
+ int Threshold(const Consensus::Params& params) const override { return 900; }
+ bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const override { return (pindex->nVersion & 0x100); }
ThresholdState GetStateFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateFor(pindexPrev, paramsDummy, cache); }
int GetStateSinceHeightFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateSinceHeightFor(pindexPrev, paramsDummy, cache); }
@@ -70,7 +69,7 @@ public:
while (vpblock.size() < height) {
CBlockIndex* pindex = new CBlockIndex();
pindex->nHeight = vpblock.size();
- pindex->pprev = vpblock.size() > 0 ? vpblock.back() : NULL;
+ pindex->pprev = vpblock.size() > 0 ? vpblock.back() : nullptr;
pindex->nTime = nTime;
pindex->nVersion = nVersion;
pindex->BuildSkip();
@@ -81,8 +80,8 @@ public:
VersionBitsTester& TestStateSinceHeight(int height) {
for (int i = 0; i < CHECKERS; i++) {
- if ((insecure_rand() & ((1 << i) - 1)) == 0) {
- BOOST_CHECK_MESSAGE(checker[i].GetStateSinceHeightFor(vpblock.empty() ? NULL : vpblock.back()) == height, strprintf("Test %i for StateSinceHeight", num));
+ if (InsecureRandBits(i) == 0) {
+ BOOST_CHECK_MESSAGE(checker[i].GetStateSinceHeightFor(vpblock.empty() ? nullptr : vpblock.back()) == height, strprintf("Test %i for StateSinceHeight", num));
}
}
num++;
@@ -91,8 +90,8 @@ public:
VersionBitsTester& TestDefined() {
for (int i = 0; i < CHECKERS; i++) {
- if ((insecure_rand() & ((1 << i) - 1)) == 0) {
- BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_DEFINED, strprintf("Test %i for DEFINED", num));
+ if (InsecureRandBits(i) == 0) {
+ BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_DEFINED, strprintf("Test %i for DEFINED", num));
}
}
num++;
@@ -101,8 +100,8 @@ public:
VersionBitsTester& TestStarted() {
for (int i = 0; i < CHECKERS; i++) {
- if ((insecure_rand() & ((1 << i) - 1)) == 0) {
- BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_STARTED, strprintf("Test %i for STARTED", num));
+ if (InsecureRandBits(i) == 0) {
+ BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_STARTED, strprintf("Test %i for STARTED", num));
}
}
num++;
@@ -111,8 +110,8 @@ public:
VersionBitsTester& TestLockedIn() {
for (int i = 0; i < CHECKERS; i++) {
- if ((insecure_rand() & ((1 << i) - 1)) == 0) {
- BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_LOCKED_IN, strprintf("Test %i for LOCKED_IN", num));
+ if (InsecureRandBits(i) == 0) {
+ BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_LOCKED_IN, strprintf("Test %i for LOCKED_IN", num));
}
}
num++;
@@ -121,8 +120,8 @@ public:
VersionBitsTester& TestActive() {
for (int i = 0; i < CHECKERS; i++) {
- if ((insecure_rand() & ((1 << i) - 1)) == 0) {
- BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_ACTIVE, strprintf("Test %i for ACTIVE", num));
+ if (InsecureRandBits(i) == 0) {
+ BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_ACTIVE, strprintf("Test %i for ACTIVE", num));
}
}
num++;
@@ -131,15 +130,15 @@ public:
VersionBitsTester& TestFailed() {
for (int i = 0; i < CHECKERS; i++) {
- if ((insecure_rand() & ((1 << i) - 1)) == 0) {
- BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_FAILED, strprintf("Test %i for FAILED", num));
+ if (InsecureRandBits(i) == 0) {
+ BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_FAILED, strprintf("Test %i for FAILED", num));
}
}
num++;
return *this;
}
- CBlockIndex * Tip() { return vpblock.size() ? vpblock.back() : NULL; }
+ CBlockIndex * Tip() { return vpblock.size() ? vpblock.back() : nullptr; }
};
BOOST_FIXTURE_TEST_SUITE(versionbits_tests, TestingSetup)
@@ -209,7 +208,8 @@ BOOST_AUTO_TEST_CASE(versionbits_test)
}
// Sanity checks of version bit deployments
- const Consensus::Params &mainnetParams = Params(CBaseChainParams::MAIN).GetConsensus();
+ const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);
+ const Consensus::Params &mainnetParams = chainParams->GetConsensus();
for (int i=0; i<(int) Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) {
uint32_t bitmask = VersionBitsMask(mainnetParams, (Consensus::DeploymentPos)i);
// Make sure that no deployment tries to set an invalid bit.
@@ -235,7 +235,8 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
{
// Check that ComputeBlockVersion will set the appropriate bit correctly
// on mainnet.
- const Consensus::Params &mainnetParams = Params(CBaseChainParams::MAIN).GetConsensus();
+ const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);
+ const Consensus::Params &mainnetParams = chainParams->GetConsensus();
// Use the TESTDUMMY deployment for testing purposes.
int64_t bit = mainnetParams.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit;
@@ -254,7 +255,7 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
// Before MedianTimePast of the chain has crossed nStartTime, the bit
// should not be set.
- CBlockIndex *lastBlock = NULL;
+ CBlockIndex *lastBlock = nullptr;
lastBlock = firstChain.Mine(2016, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);
@@ -292,7 +293,7 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
blocksToMine--;
nTime += 600;
nHeight += 1;
- };
+ }
nTime = nTimeout;
// FAILED is only triggered at the end of a period, so CBV should be setting
@@ -313,20 +314,20 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
// Mine one period worth of blocks, and check that the bit will be on for the
// next period.
- lastBlock = secondChain.Mine(2016, nStartTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ lastBlock = secondChain.Mine(2016, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
// Mine another period worth of blocks, signaling the new bit.
- lastBlock = secondChain.Mine(4032, nStartTime, VERSIONBITS_TOP_BITS | (1<<bit)).Tip();
+ lastBlock = secondChain.Mine(4032, nTime, VERSIONBITS_TOP_BITS | (1<<bit)).Tip();
// After one period of setting the bit on each block, it should have locked in.
// We keep setting the bit for one more period though, until activation.
BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
// Now check that we keep mining the block until the end of this period, and
// then stop at the beginning of the next period.
- lastBlock = secondChain.Mine(6047, nStartTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ lastBlock = secondChain.Mine(6047, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
- lastBlock = secondChain.Mine(6048, nStartTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ lastBlock = secondChain.Mine(6048, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);
// Finally, verify that after a soft fork has activated, CBV no longer uses
diff --git a/src/timedata.cpp b/src/timedata.cpp
index c72252e6d8..5113bb60db 100644
--- a/src/timedata.cpp
+++ b/src/timedata.cpp
@@ -15,9 +15,6 @@
#include "utilstrencodings.h"
#include "warnings.h"
-#include <boost/foreach.hpp>
-
-using namespace std;
static CCriticalSection cs_nTimeOffset;
static int64_t nTimeOffset = 0;
@@ -51,7 +48,7 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample)
{
LOCK(cs_nTimeOffset);
// Ignore duplicates
- static set<CNetAddr> setKnown;
+ static std::set<CNetAddr> setKnown;
if (setKnown.size() == BITCOIN_TIMEDATA_MAX_SAMPLES)
return;
if (!setKnown.insert(ip).second)
@@ -60,7 +57,7 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample)
// Add data
static CMedianFilter<int64_t> vTimeOffsets(BITCOIN_TIMEDATA_MAX_SAMPLES, 0);
vTimeOffsets.input(nOffsetSample);
- LogPrint("net","added time data, samples %d, offset %+d (%+d minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample/60);
+ LogPrint(BCLog::NET,"added time data, samples %d, offset %+d (%+d minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample/60);
// There is a known issue here (see issue #4521):
//
@@ -84,7 +81,7 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample)
int64_t nMedian = vTimeOffsets.median();
std::vector<int64_t> vSorted = vTimeOffsets.sorted();
// Only let other nodes change our time by so much
- if (abs64(nMedian) <= std::max<int64_t>(0, GetArg("-maxtimeadjustment", DEFAULT_MAX_TIME_ADJUSTMENT)))
+ if (abs64(nMedian) <= std::max<int64_t>(0, gArgs.GetArg("-maxtimeadjustment", DEFAULT_MAX_TIME_ADJUSTMENT)))
{
nTimeOffset = nMedian;
}
@@ -97,7 +94,7 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample)
{
// If nobody has a time different than ours but within 5 minutes of ours, give a warning
bool fMatch = false;
- BOOST_FOREACH(int64_t nOffset, vSorted)
+ for (int64_t nOffset : vSorted)
if (nOffset != 0 && abs64(nOffset) < 5 * 60)
fMatch = true;
@@ -110,11 +107,14 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample)
}
}
}
-
- BOOST_FOREACH(int64_t n, vSorted)
- LogPrint("net", "%+d ", n);
- LogPrint("net", "| ");
-
- LogPrint("net", "nTimeOffset = %+d (%+d minutes)\n", nTimeOffset, nTimeOffset/60);
+
+ if (LogAcceptCategory(BCLog::NET)) {
+ for (int64_t n : vSorted) {
+ LogPrint(BCLog::NET, "%+d ", n);
+ }
+ LogPrint(BCLog::NET, "| ");
+
+ LogPrint(BCLog::NET, "nTimeOffset = %+d (%+d minutes)\n", nTimeOffset, nTimeOffset/60);
+ }
}
}
diff --git a/src/timedata.h b/src/timedata.h
index 4a2eab3487..bc5451b19b 100644
--- a/src/timedata.h
+++ b/src/timedata.h
@@ -27,9 +27,9 @@ private:
unsigned int nSize;
public:
- CMedianFilter(unsigned int size, T initial_value) : nSize(size)
+ CMedianFilter(unsigned int _size, T initial_value) : nSize(_size)
{
- vValues.reserve(size);
+ vValues.reserve(_size);
vValues.push_back(initial_value);
vSorted = vValues;
}
@@ -48,14 +48,14 @@ public:
T median() const
{
- int size = vSorted.size();
- assert(size > 0);
- if (size & 1) // Odd number of elements
+ int vSortedSize = vSorted.size();
+ assert(vSortedSize > 0);
+ if (vSortedSize & 1) // Odd number of elements
{
- return vSorted[size / 2];
+ return vSorted[vSortedSize / 2];
} else // Even number of elements
{
- return (vSorted[size / 2 - 1] + vSorted[size / 2]) / 2;
+ return (vSorted[vSortedSize / 2 - 1] + vSorted[vSortedSize / 2]) / 2;
}
}
diff --git a/src/tinyformat.h b/src/tinyformat.h
index 17f0360c42..2e453e56bb 100644
--- a/src/tinyformat.h
+++ b/src/tinyformat.h
@@ -123,7 +123,7 @@ namespace tinyformat {}
namespace tfm = tinyformat;
// Error handling; calls assert() by default.
-#define TINYFORMAT_ERROR(reasonString) throw std::runtime_error(reasonString)
+#define TINYFORMAT_ERROR(reasonString) throw tinyformat::format_error(reasonString)
// Define for C++11 variadic templates which make the code shorter & more
// general. If you don't define this, C++11 support is autodetected below.
@@ -164,6 +164,13 @@ namespace tfm = tinyformat;
namespace tinyformat {
+class format_error: public std::runtime_error
+{
+public:
+ explicit format_error(const std::string &what): std::runtime_error(what) {
+ }
+};
+
//------------------------------------------------------------------------------
namespace detail {
@@ -491,7 +498,7 @@ class FormatArg
FormatArg() {}
template<typename T>
- FormatArg(const T& value)
+ explicit FormatArg(const T& value)
: m_value(static_cast<const void*>(&value)),
m_formatImpl(&formatImpl<T>),
m_toIntImpl(&toIntImpl<T>)
@@ -860,7 +867,7 @@ class FormatListN : public FormatList
public:
#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
template<typename... Args>
- FormatListN(const Args&... args)
+ explicit FormatListN(const Args&... args)
: FormatList(&m_formatterStore[0], N),
m_formatterStore { FormatArg(args)... }
{ static_assert(sizeof...(args) == N, "Number of args must be N"); }
@@ -869,7 +876,7 @@ class FormatListN : public FormatList
# define TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR(n) \
\
template<TINYFORMAT_ARGTYPES(n)> \
- FormatListN(TINYFORMAT_VARARGS(n)) \
+ explicit FormatListN(TINYFORMAT_VARARGS(n)) \
: FormatList(&m_formatterStore[0], n) \
{ assert(n == N); init(0, TINYFORMAT_PASSARGS(n)); } \
\
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index 5571b7de44..1cea197666 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -1,4 +1,5 @@
// Copyright (c) 2015-2016 The Bitcoin Core developers
+// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -14,11 +15,8 @@
#include <set>
#include <stdlib.h>
-#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/signals2/signal.hpp>
-#include <boost/foreach.hpp>
-#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/replace.hpp>
@@ -73,12 +71,12 @@ public:
class TorControlConnection
{
public:
- typedef boost::function<void(TorControlConnection&)> ConnectionCB;
- typedef boost::function<void(TorControlConnection &,const TorControlReply &)> ReplyHandlerCB;
+ typedef std::function<void(TorControlConnection&)> ConnectionCB;
+ typedef std::function<void(TorControlConnection &,const TorControlReply &)> ReplyHandlerCB;
/** Create a new TorControlConnection.
*/
- TorControlConnection(struct event_base *base);
+ explicit TorControlConnection(struct event_base *base);
~TorControlConnection();
/**
@@ -105,9 +103,9 @@ public:
boost::signals2::signal<void(TorControlConnection &,const TorControlReply &)> async_handler;
private:
/** Callback when ready for use */
- boost::function<void(TorControlConnection&)> connected;
+ std::function<void(TorControlConnection&)> connected;
/** Callback when connection lost */
- boost::function<void(TorControlConnection&)> disconnected;
+ std::function<void(TorControlConnection&)> disconnected;
/** Libevent event base */
struct event_base *base;
/** Connection to control socket */
@@ -123,7 +121,7 @@ private:
};
TorControlConnection::TorControlConnection(struct event_base *_base):
- base(_base), b_conn(0)
+ base(_base), b_conn(nullptr)
{
}
@@ -140,8 +138,8 @@ void TorControlConnection::readcb(struct bufferevent *bev, void *ctx)
size_t n_read_out = 0;
char *line;
assert(input);
- // If there is not a whole line to read, evbuffer_readln returns NULL
- while((line = evbuffer_readln(input, &n_read_out, EVBUFFER_EOL_CRLF)) != NULL)
+ // If there is not a whole line to read, evbuffer_readln returns nullptr
+ while((line = evbuffer_readln(input, &n_read_out, EVBUFFER_EOL_CRLF)) != nullptr)
{
std::string s(line, n_read_out);
free(line);
@@ -163,7 +161,7 @@ void TorControlConnection::readcb(struct bufferevent *bev, void *ctx)
self->reply_handlers.front()(*self, self->message);
self->reply_handlers.pop_front();
} else {
- LogPrint("tor", "tor: Received unexpected sync reply %i\n", self->message.code);
+ LogPrint(BCLog::TOR, "tor: Received unexpected sync reply %i\n", self->message.code);
}
}
self->message.Clear();
@@ -182,13 +180,14 @@ void TorControlConnection::eventcb(struct bufferevent *bev, short what, void *ct
{
TorControlConnection *self = (TorControlConnection*)ctx;
if (what & BEV_EVENT_CONNECTED) {
- LogPrint("tor", "tor: Successfully connected!\n");
+ LogPrint(BCLog::TOR, "tor: Successfully connected!\n");
self->connected(*self);
} else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
- if (what & BEV_EVENT_ERROR)
- LogPrint("tor", "tor: Error connecting to Tor control socket\n");
- else
- LogPrint("tor", "tor: End of stream\n");
+ if (what & BEV_EVENT_ERROR) {
+ LogPrint(BCLog::TOR, "tor: Error connecting to Tor control socket\n");
+ } else {
+ LogPrint(BCLog::TOR, "tor: End of stream\n");
+ }
self->Disconnect();
self->disconnected(*self);
}
@@ -211,7 +210,7 @@ bool TorControlConnection::Connect(const std::string &target, const ConnectionCB
b_conn = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
if (!b_conn)
return false;
- bufferevent_setcb(b_conn, TorControlConnection::readcb, NULL, TorControlConnection::eventcb, this);
+ bufferevent_setcb(b_conn, TorControlConnection::readcb, nullptr, TorControlConnection::eventcb, this);
bufferevent_enable(b_conn, EV_READ|EV_WRITE);
this->connected = _connected;
this->disconnected = _disconnected;
@@ -228,7 +227,7 @@ bool TorControlConnection::Disconnect()
{
if (b_conn)
bufferevent_free(b_conn);
- b_conn = 0;
+ b_conn = nullptr;
return true;
}
@@ -249,6 +248,8 @@ bool TorControlConnection::Command(const std::string &cmd, const ReplyHandlerCB&
/* Split reply line in the form 'AUTH METHODS=...' into a type
* 'AUTH' and arguments 'METHODS=...'.
+ * Grammar is implicitly defined in https://spec.torproject.org/control-spec by
+ * the server reply formats for PROTOCOLINFO (S3.21) and AUTHCHALLENGE (S3.24).
*/
static std::pair<std::string,std::string> SplitTorReplyLine(const std::string &s)
{
@@ -264,6 +265,10 @@ static std::pair<std::string,std::string> SplitTorReplyLine(const std::string &s
}
/** Parse reply arguments in the form 'METHODS=COOKIE,SAFECOOKIE COOKIEFILE=".../control_auth_cookie"'.
+ * Returns a map of keys to values, or an empty map if there was an error.
+ * Grammar is implicitly defined in https://spec.torproject.org/control-spec by
+ * the server reply formats for PROTOCOLINFO (S3.21), AUTHCHALLENGE (S3.24),
+ * and ADD_ONION (S3.27). See also sections 2.1 and 2.3.
*/
static std::map<std::string,std::string> ParseTorReplyMapping(const std::string &s)
{
@@ -271,28 +276,74 @@ static std::map<std::string,std::string> ParseTorReplyMapping(const std::string
size_t ptr=0;
while (ptr < s.size()) {
std::string key, value;
- while (ptr < s.size() && s[ptr] != '=') {
+ while (ptr < s.size() && s[ptr] != '=' && s[ptr] != ' ') {
key.push_back(s[ptr]);
++ptr;
}
if (ptr == s.size()) // unexpected end of line
return std::map<std::string,std::string>();
+ if (s[ptr] == ' ') // The remaining string is an OptArguments
+ break;
++ptr; // skip '='
if (ptr < s.size() && s[ptr] == '"') { // Quoted string
- ++ptr; // skip '='
+ ++ptr; // skip opening '"'
bool escape_next = false;
- while (ptr < s.size() && (!escape_next && s[ptr] != '"')) {
- escape_next = (s[ptr] == '\\');
+ while (ptr < s.size() && (escape_next || s[ptr] != '"')) {
+ // Repeated backslashes must be interpreted as pairs
+ escape_next = (s[ptr] == '\\' && !escape_next);
value.push_back(s[ptr]);
++ptr;
}
if (ptr == s.size()) // unexpected end of line
return std::map<std::string,std::string>();
++ptr; // skip closing '"'
- /* TODO: unescape value - according to the spec this depends on the
- * context, some strings use C-LogPrintf style escape codes, some
- * don't. So may be better handled at the call site.
+ /**
+ * Unescape value. Per https://spec.torproject.org/control-spec section 2.1.1:
+ *
+ * For future-proofing, controller implementors MAY use the following
+ * rules to be compatible with buggy Tor implementations and with
+ * future ones that implement the spec as intended:
+ *
+ * Read \n \t \r and \0 ... \377 as C escapes.
+ * Treat a backslash followed by any other character as that character.
*/
+ std::string escaped_value;
+ for (size_t i = 0; i < value.size(); ++i) {
+ if (value[i] == '\\') {
+ // This will always be valid, because if the QuotedString
+ // ended in an odd number of backslashes, then the parser
+ // would already have returned above, due to a missing
+ // terminating double-quote.
+ ++i;
+ if (value[i] == 'n') {
+ escaped_value.push_back('\n');
+ } else if (value[i] == 't') {
+ escaped_value.push_back('\t');
+ } else if (value[i] == 'r') {
+ escaped_value.push_back('\r');
+ } else if ('0' <= value[i] && value[i] <= '7') {
+ size_t j;
+ // Octal escape sequences have a limit of three octal digits,
+ // but terminate at the first character that is not a valid
+ // octal digit if encountered sooner.
+ for (j = 1; j < 3 && (i+j) < value.size() && '0' <= value[i+j] && value[i+j] <= '7'; ++j) {}
+ // Tor restricts first digit to 0-3 for three-digit octals.
+ // A leading digit of 4-7 would therefore be interpreted as
+ // a two-digit octal.
+ if (j == 3 && value[i] > '3') {
+ j--;
+ }
+ escaped_value.push_back(strtol(value.substr(i, j).c_str(), nullptr, 8));
+ // Account for automatic incrementing at loop end
+ i += j - 1;
+ } else {
+ escaped_value.push_back(value[i]);
+ }
+ } else {
+ escaped_value.push_back(value[i]);
+ }
+ }
+ value = escaped_value;
} else { // Unquoted value. Note that values can contain '=' at will, just no spaces
while (ptr < s.size() && s[ptr] != ' ') {
value.push_back(s[ptr]);
@@ -313,15 +364,21 @@ static std::map<std::string,std::string> ParseTorReplyMapping(const std::string
* @param maxsize Puts a maximum size limit on the file that is read. If the file is larger than this, truncated data
* (with len > maxsize) will be returned.
*/
-static std::pair<bool,std::string> ReadBinaryFile(const std::string &filename, size_t maxsize=std::numeric_limits<size_t>::max())
+static std::pair<bool,std::string> ReadBinaryFile(const fs::path &filename, size_t maxsize=std::numeric_limits<size_t>::max())
{
- FILE *f = fopen(filename.c_str(), "rb");
- if (f == NULL)
+ FILE *f = fsbridge::fopen(filename, "rb");
+ if (f == nullptr)
return std::make_pair(false,"");
std::string retval;
char buffer[128];
size_t n;
while ((n=fread(buffer, 1, sizeof(buffer), f)) > 0) {
+ // Check for reading errors so we don't return any data if we couldn't
+ // read the entire file (or up to maxsize)
+ if (ferror(f)) {
+ fclose(f);
+ return std::make_pair(false,"");
+ }
retval.append(buffer, buffer+n);
if (retval.size() > maxsize)
break;
@@ -333,10 +390,10 @@ static std::pair<bool,std::string> ReadBinaryFile(const std::string &filename, s
/** Write contents of std::string to a file.
* @return true on success.
*/
-static bool WriteBinaryFile(const std::string &filename, const std::string &data)
+static bool WriteBinaryFile(const fs::path &filename, const std::string &data)
{
- FILE *f = fopen(filename.c_str(), "wb");
- if (f == NULL)
+ FILE *f = fsbridge::fopen(filename, "wb");
+ if (f == nullptr)
return false;
if (fwrite(data.data(), 1, data.size(), f) != data.size()) {
fclose(f);
@@ -349,7 +406,7 @@ static bool WriteBinaryFile(const std::string &filename, const std::string &data
/****** Bitcoin specific TorController implementation ********/
/** Controller that connects to Tor control socket, authenticate, then create
- * and maintain a ephemeral hidden service.
+ * and maintain an ephemeral hidden service.
*/
class TorController
{
@@ -358,7 +415,7 @@ public:
~TorController();
/** Get name fo file to store private key in */
- std::string GetPrivateKeyFile();
+ fs::path GetPrivateKeyFile();
/** Reconnect, after getting disconnected */
void Reconnect();
@@ -372,7 +429,7 @@ private:
struct event *reconnect_ev;
float reconnect_timeout;
CService service;
- /** Cooie for SAFECOOKIE auth */
+ /** Cookie for SAFECOOKIE auth */
std::vector<uint8_t> cookie;
/** ClientNonce for SAFECOOKIE auth */
std::vector<uint8_t> clientNonce;
@@ -410,7 +467,7 @@ TorController::TorController(struct event_base* _base, const std::string& _targe
// Read service private key if cached
std::pair<bool,std::string> pkf = ReadBinaryFile(GetPrivateKeyFile());
if (pkf.first) {
- LogPrint("tor", "tor: Reading cached private key from %s\n", GetPrivateKeyFile());
+ LogPrint(BCLog::TOR, "tor: Reading cached private key from %s\n", GetPrivateKeyFile().string());
private_key = pkf.second;
}
}
@@ -419,7 +476,7 @@ TorController::~TorController()
{
if (reconnect_ev) {
event_free(reconnect_ev);
- reconnect_ev = 0;
+ reconnect_ev = nullptr;
}
if (service.IsValid()) {
RemoveLocal(service);
@@ -429,8 +486,8 @@ TorController::~TorController()
void TorController::add_onion_cb(TorControlConnection& _conn, const TorControlReply& reply)
{
if (reply.code == 250) {
- LogPrint("tor", "tor: ADD_ONION successful\n");
- BOOST_FOREACH(const std::string &s, reply.lines) {
+ LogPrint(BCLog::TOR, "tor: ADD_ONION successful\n");
+ for (const std::string &s : reply.lines) {
std::map<std::string,std::string> m = ParseTorReplyMapping(s);
std::map<std::string,std::string>::iterator i;
if ((i = m.find("ServiceID")) != m.end())
@@ -438,12 +495,19 @@ void TorController::add_onion_cb(TorControlConnection& _conn, const TorControlRe
if ((i = m.find("PrivateKey")) != m.end())
private_key = i->second;
}
+ if (service_id.empty()) {
+ LogPrintf("tor: Error parsing ADD_ONION parameters:\n");
+ for (const std::string &s : reply.lines) {
+ LogPrintf(" %s\n", SanitizeString(s));
+ }
+ return;
+ }
service = LookupNumeric(std::string(service_id+".onion").c_str(), GetListenPort());
LogPrintf("tor: Got service ID %s, advertising service %s\n", service_id, service.ToString());
if (WriteBinaryFile(GetPrivateKeyFile(), private_key)) {
- LogPrint("tor", "tor: Cached service private key to %s\n", GetPrivateKeyFile());
+ LogPrint(BCLog::TOR, "tor: Cached service private key to %s\n", GetPrivateKeyFile().string());
} else {
- LogPrintf("tor: Error writing service private key to %s\n", GetPrivateKeyFile());
+ LogPrintf("tor: Error writing service private key to %s\n", GetPrivateKeyFile().string());
}
AddLocal(service, LOCAL_MANUAL);
// ... onion requested - keep connection open
@@ -457,11 +521,11 @@ void TorController::add_onion_cb(TorControlConnection& _conn, const TorControlRe
void TorController::auth_cb(TorControlConnection& _conn, const TorControlReply& reply)
{
if (reply.code == 250) {
- LogPrint("tor", "tor: Authentication successful\n");
+ LogPrint(BCLog::TOR, "tor: Authentication successful\n");
// Now that we know Tor is running setup the proxy for onion addresses
// if -onion isn't set to something else.
- if (GetArg("-onion", "") == "") {
+ if (gArgs.GetArg("-onion", "") == "") {
CService resolved(LookupNumeric("127.0.0.1", 9050));
proxyType addrOnion = proxyType(resolved, true);
SetProxy(NET_TOR, addrOnion);
@@ -511,13 +575,17 @@ static std::vector<uint8_t> ComputeResponse(const std::string &key, const std::v
void TorController::authchallenge_cb(TorControlConnection& _conn, const TorControlReply& reply)
{
if (reply.code == 250) {
- LogPrint("tor", "tor: SAFECOOKIE authentication challenge successful\n");
+ LogPrint(BCLog::TOR, "tor: SAFECOOKIE authentication challenge successful\n");
std::pair<std::string,std::string> l = SplitTorReplyLine(reply.lines[0]);
if (l.first == "AUTHCHALLENGE") {
std::map<std::string,std::string> m = ParseTorReplyMapping(l.second);
+ if (m.empty()) {
+ LogPrintf("tor: Error parsing AUTHCHALLENGE parameters: %s\n", SanitizeString(l.second));
+ return;
+ }
std::vector<uint8_t> serverHash = ParseHex(m["SERVERHASH"]);
std::vector<uint8_t> serverNonce = ParseHex(m["SERVERNONCE"]);
- LogPrint("tor", "tor: AUTHCHALLENGE ServerHash %s ServerNonce %s\n", HexStr(serverHash), HexStr(serverNonce));
+ LogPrint(BCLog::TOR, "tor: AUTHCHALLENGE ServerHash %s ServerNonce %s\n", HexStr(serverHash), HexStr(serverNonce));
if (serverNonce.size() != 32) {
LogPrintf("tor: ServerNonce is not 32 bytes, as required by spec\n");
return;
@@ -549,7 +617,7 @@ void TorController::protocolinfo_cb(TorControlConnection& _conn, const TorContro
* 250-AUTH METHODS=NULL
* 250-AUTH METHODS=HASHEDPASSWORD
*/
- BOOST_FOREACH(const std::string &s, reply.lines) {
+ for (const std::string &s : reply.lines) {
std::pair<std::string,std::string> l = SplitTorReplyLine(s);
if (l.first == "AUTH") {
std::map<std::string,std::string> m = ParseTorReplyMapping(l.second);
@@ -562,39 +630,39 @@ void TorController::protocolinfo_cb(TorControlConnection& _conn, const TorContro
std::map<std::string,std::string> m = ParseTorReplyMapping(l.second);
std::map<std::string,std::string>::iterator i;
if ((i = m.find("Tor")) != m.end()) {
- LogPrint("tor", "tor: Connected to Tor version %s\n", i->second);
+ LogPrint(BCLog::TOR, "tor: Connected to Tor version %s\n", i->second);
}
}
}
- BOOST_FOREACH(const std::string &s, methods) {
- LogPrint("tor", "tor: Supported authentication method: %s\n", s);
+ for (const std::string &s : methods) {
+ LogPrint(BCLog::TOR, "tor: Supported authentication method: %s\n", s);
}
// Prefer NULL, otherwise SAFECOOKIE. If a password is provided, use HASHEDPASSWORD
/* Authentication:
* cookie: hex-encoded ~/.tor/control_auth_cookie
* password: "password"
*/
- std::string torpassword = GetArg("-torpassword", "");
+ std::string torpassword = gArgs.GetArg("-torpassword", "");
if (!torpassword.empty()) {
if (methods.count("HASHEDPASSWORD")) {
- LogPrint("tor", "tor: Using HASHEDPASSWORD authentication\n");
+ LogPrint(BCLog::TOR, "tor: Using HASHEDPASSWORD authentication\n");
boost::replace_all(torpassword, "\"", "\\\"");
_conn.Command("AUTHENTICATE \"" + torpassword + "\"", boost::bind(&TorController::auth_cb, this, _1, _2));
} else {
LogPrintf("tor: Password provided with -torpassword, but HASHEDPASSWORD authentication is not available\n");
}
} else if (methods.count("NULL")) {
- LogPrint("tor", "tor: Using NULL authentication\n");
+ LogPrint(BCLog::TOR, "tor: Using NULL authentication\n");
_conn.Command("AUTHENTICATE", boost::bind(&TorController::auth_cb, this, _1, _2));
} else if (methods.count("SAFECOOKIE")) {
// Cookie: hexdump -e '32/1 "%02x""\n"' ~/.tor/control_auth_cookie
- LogPrint("tor", "tor: Using SAFECOOKIE authentication, reading cookie authentication from %s\n", cookiefile);
+ LogPrint(BCLog::TOR, "tor: Using SAFECOOKIE authentication, reading cookie authentication from %s\n", cookiefile);
std::pair<bool,std::string> status_cookie = ReadBinaryFile(cookiefile, TOR_COOKIE_SIZE);
if (status_cookie.first && status_cookie.second.size() == TOR_COOKIE_SIZE) {
// _conn.Command("AUTHENTICATE " + HexStr(status_cookie.second), boost::bind(&TorController::auth_cb, this, _1, _2));
cookie = std::vector<uint8_t>(status_cookie.second.begin(), status_cookie.second.end());
clientNonce = std::vector<uint8_t>(TOR_NONCE_SIZE, 0);
- GetRandBytes(&clientNonce[0], TOR_NONCE_SIZE);
+ GetRandBytes(clientNonce.data(), TOR_NONCE_SIZE);
_conn.Command("AUTHCHALLENGE SAFECOOKIE " + HexStr(clientNonce), boost::bind(&TorController::authchallenge_cb, this, _1, _2));
} else {
if (status_cookie.first) {
@@ -630,7 +698,7 @@ void TorController::disconnected_cb(TorControlConnection& _conn)
if (!reconnect)
return;
- LogPrint("tor", "tor: Not connected to Tor control port %s, trying to reconnect\n", target);
+ LogPrint(BCLog::TOR, "tor: Not connected to Tor control port %s, trying to reconnect\n", target);
// Single-shot timer for reconnect. Use exponential backoff.
struct timeval time = MillisToTimeval(int64_t(reconnect_timeout * 1000.0));
@@ -650,9 +718,9 @@ void TorController::Reconnect()
}
}
-std::string TorController::GetPrivateKeyFile()
+fs::path TorController::GetPrivateKeyFile()
{
- return (GetDataDir() / "onion_private_key").string();
+ return GetDataDir() / "onion_private_key";
}
void TorController::reconnect_cb(evutil_socket_t fd, short what, void *arg)
@@ -662,26 +730,26 @@ void TorController::reconnect_cb(evutil_socket_t fd, short what, void *arg)
}
/****** Thread ********/
-struct event_base *base;
-boost::thread torControlThread;
+static struct event_base *gBase;
+static boost::thread torControlThread;
static void TorControlThread()
{
- TorController ctrl(base, GetArg("-torcontrol", DEFAULT_TOR_CONTROL));
+ TorController ctrl(gBase, gArgs.GetArg("-torcontrol", DEFAULT_TOR_CONTROL));
- event_base_dispatch(base);
+ event_base_dispatch(gBase);
}
void StartTorControl(boost::thread_group& threadGroup, CScheduler& scheduler)
{
- assert(!base);
+ assert(!gBase);
#ifdef WIN32
evthread_use_windows_threads();
#else
evthread_use_pthreads();
#endif
- base = event_base_new();
- if (!base) {
+ gBase = event_base_new();
+ if (!gBase) {
LogPrintf("tor: Unable to create event_base\n");
return;
}
@@ -691,18 +759,18 @@ void StartTorControl(boost::thread_group& threadGroup, CScheduler& scheduler)
void InterruptTorControl()
{
- if (base) {
+ if (gBase) {
LogPrintf("tor: Thread interrupt\n");
- event_base_loopbreak(base);
+ event_base_loopbreak(gBase);
}
}
void StopTorControl()
{
- if (base) {
+ if (gBase) {
torControlThread.join();
- event_base_free(base);
- base = 0;
+ event_base_free(gBase);
+ gBase = nullptr;
}
}
diff --git a/src/txdb.cpp b/src/txdb.cpp
index c223abd590..134bb8721b 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -7,36 +7,63 @@
#include "chainparams.h"
#include "hash.h"
+#include "random.h"
#include "pow.h"
#include "uint256.h"
+#include "util.h"
+#include "ui_interface.h"
+#include "init.h"
#include <stdint.h>
#include <boost/thread.hpp>
-using namespace std;
-
+static const char DB_COIN = 'C';
static const char DB_COINS = 'c';
static const char DB_BLOCK_FILES = 'f';
static const char DB_TXINDEX = 't';
static const char DB_BLOCK_INDEX = 'b';
static const char DB_BEST_BLOCK = 'B';
+static const char DB_HEAD_BLOCKS = 'H';
static const char DB_FLAG = 'F';
static const char DB_REINDEX_FLAG = 'R';
static const char DB_LAST_BLOCK = 'l';
+namespace {
+
+struct CoinEntry {
+ COutPoint* outpoint;
+ char key;
+ explicit CoinEntry(const COutPoint* ptr) : outpoint(const_cast<COutPoint*>(ptr)), key(DB_COIN) {}
+
+ template<typename Stream>
+ void Serialize(Stream &s) const {
+ s << key;
+ s << outpoint->hash;
+ s << VARINT(outpoint->n);
+ }
+
+ template<typename Stream>
+ void Unserialize(Stream& s) {
+ s >> key;
+ s >> outpoint->hash;
+ s >> VARINT(outpoint->n);
+ }
+};
+
+}
CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe, true)
{
}
-bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) const {
- return db.Read(make_pair(DB_COINS, txid), coins);
+bool CCoinsViewDB::GetCoin(const COutPoint &outpoint, Coin &coin) const {
+ return db.Read(CoinEntry(&outpoint), coin);
}
-bool CCoinsViewDB::HaveCoins(const uint256 &txid) const {
- return db.Exists(make_pair(DB_COINS, txid));
+bool CCoinsViewDB::HaveCoin(const COutPoint &outpoint) const {
+ return db.Exists(CoinEntry(&outpoint));
}
uint256 CCoinsViewDB::GetBestBlock() const {
@@ -46,34 +73,85 @@ uint256 CCoinsViewDB::GetBestBlock() const {
return hashBestChain;
}
+std::vector<uint256> CCoinsViewDB::GetHeadBlocks() const {
+ std::vector<uint256> vhashHeadBlocks;
+ if (!db.Read(DB_HEAD_BLOCKS, vhashHeadBlocks)) {
+ return std::vector<uint256>();
+ }
+ return vhashHeadBlocks;
+}
+
bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
CDBBatch batch(db);
size_t count = 0;
size_t changed = 0;
+ size_t batch_size = (size_t)gArgs.GetArg("-dbbatchsize", nDefaultDbBatchSize);
+ int crash_simulate = gArgs.GetArg("-dbcrashratio", 0);
+ assert(!hashBlock.IsNull());
+
+ uint256 old_tip = GetBestBlock();
+ if (old_tip.IsNull()) {
+ // We may be in the middle of replaying.
+ std::vector<uint256> old_heads = GetHeadBlocks();
+ if (old_heads.size() == 2) {
+ assert(old_heads[0] == hashBlock);
+ old_tip = old_heads[1];
+ }
+ }
+
+ // In the first batch, mark the database as being in the middle of a
+ // transition from old_tip to hashBlock.
+ // A vector is used for future extensibility, as we may want to support
+ // interrupting after partial writes from multiple independent reorgs.
+ batch.Erase(DB_BEST_BLOCK);
+ batch.Write(DB_HEAD_BLOCKS, std::vector<uint256>{hashBlock, old_tip});
+
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
if (it->second.flags & CCoinsCacheEntry::DIRTY) {
- if (it->second.coins.IsPruned())
- batch.Erase(make_pair(DB_COINS, it->first));
+ CoinEntry entry(&it->first);
+ if (it->second.coin.IsSpent())
+ batch.Erase(entry);
else
- batch.Write(make_pair(DB_COINS, it->first), it->second.coins);
+ batch.Write(entry, it->second.coin);
changed++;
}
count++;
CCoinsMap::iterator itOld = it++;
mapCoins.erase(itOld);
+ if (batch.SizeEstimate() > batch_size) {
+ LogPrint(BCLog::COINDB, "Writing partial batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0));
+ db.WriteBatch(batch);
+ batch.Clear();
+ if (crash_simulate) {
+ static FastRandomContext rng;
+ if (rng.randrange(crash_simulate) == 0) {
+ LogPrintf("Simulating a crash. Goodbye.\n");
+ _Exit(0);
+ }
+ }
+ }
}
- if (!hashBlock.IsNull())
- batch.Write(DB_BEST_BLOCK, hashBlock);
- LogPrint("coindb", "Committing %u changed transactions (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
- return db.WriteBatch(batch);
+ // In the last batch, mark the database as consistent with hashBlock again.
+ batch.Erase(DB_HEAD_BLOCKS);
+ batch.Write(DB_BEST_BLOCK, hashBlock);
+
+ LogPrint(BCLog::COINDB, "Writing final batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0));
+ bool ret = db.WriteBatch(batch);
+ LogPrint(BCLog::COINDB, "Committed %u changed transaction outputs (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
+ return ret;
+}
+
+size_t CCoinsViewDB::EstimateSize() const
+{
+ return db.EstimateSize(DB_COIN, (char)(DB_COIN+1));
}
CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) {
}
bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
- return Read(make_pair(DB_BLOCK_FILES, nFile), info);
+ return Read(std::make_pair(DB_BLOCK_FILES, nFile), info);
}
bool CBlockTreeDB::WriteReindexing(bool fReindexing) {
@@ -94,29 +172,35 @@ bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
CCoinsViewCursor *CCoinsViewDB::Cursor() const
{
- CCoinsViewDBCursor *i = new CCoinsViewDBCursor(const_cast<CDBWrapper*>(&db)->NewIterator(), GetBestBlock());
+ CCoinsViewDBCursor *i = new CCoinsViewDBCursor(const_cast<CDBWrapper&>(db).NewIterator(), GetBestBlock());
/* It seems that there are no "const iterators" for LevelDB. Since we
only need read operations on it, use a const-cast to get around
that restriction. */
- i->pcursor->Seek(DB_COINS);
+ i->pcursor->Seek(DB_COIN);
// Cache key of first record
- i->pcursor->GetKey(i->keyTmp);
+ if (i->pcursor->Valid()) {
+ CoinEntry entry(&i->keyTmp.second);
+ i->pcursor->GetKey(entry);
+ i->keyTmp.first = entry.key;
+ } else {
+ i->keyTmp.first = 0; // Make sure Valid() and GetKey() return false
+ }
return i;
}
-bool CCoinsViewDBCursor::GetKey(uint256 &key) const
+bool CCoinsViewDBCursor::GetKey(COutPoint &key) const
{
// Return cached key
- if (keyTmp.first == DB_COINS) {
+ if (keyTmp.first == DB_COIN) {
key = keyTmp.second;
return true;
}
return false;
}
-bool CCoinsViewDBCursor::GetValue(CCoins &coins) const
+bool CCoinsViewDBCursor::GetValue(Coin &coin) const
{
- return pcursor->GetValue(coins);
+ return pcursor->GetValue(coin);
}
unsigned int CCoinsViewDBCursor::GetValueSize() const
@@ -126,36 +210,40 @@ unsigned int CCoinsViewDBCursor::GetValueSize() const
bool CCoinsViewDBCursor::Valid() const
{
- return keyTmp.first == DB_COINS;
+ return keyTmp.first == DB_COIN;
}
void CCoinsViewDBCursor::Next()
{
pcursor->Next();
- if (!pcursor->Valid() || !pcursor->GetKey(keyTmp))
+ CoinEntry entry(&keyTmp.second);
+ if (!pcursor->Valid() || !pcursor->GetKey(entry)) {
keyTmp.first = 0; // Invalidate cached key after last record so that Valid() and GetKey() return false
+ } else {
+ keyTmp.first = entry.key;
+ }
}
bool CBlockTreeDB::WriteBatchSync(const std::vector<std::pair<int, const CBlockFileInfo*> >& fileInfo, int nLastFile, const std::vector<const CBlockIndex*>& blockinfo) {
CDBBatch batch(*this);
for (std::vector<std::pair<int, const CBlockFileInfo*> >::const_iterator it=fileInfo.begin(); it != fileInfo.end(); it++) {
- batch.Write(make_pair(DB_BLOCK_FILES, it->first), *it->second);
+ batch.Write(std::make_pair(DB_BLOCK_FILES, it->first), *it->second);
}
batch.Write(DB_LAST_BLOCK, nLastFile);
for (std::vector<const CBlockIndex*>::const_iterator it=blockinfo.begin(); it != blockinfo.end(); it++) {
- batch.Write(make_pair(DB_BLOCK_INDEX, (*it)->GetBlockHash()), CDiskBlockIndex(*it));
+ batch.Write(std::make_pair(DB_BLOCK_INDEX, (*it)->GetBlockHash()), CDiskBlockIndex(*it));
}
return WriteBatch(batch, true);
}
bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) {
- return Read(make_pair(DB_TXINDEX, txid), pos);
+ return Read(std::make_pair(DB_TXINDEX, txid), pos);
}
bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> >&vect) {
CDBBatch batch(*this);
for (std::vector<std::pair<uint256,CDiskTxPos> >::const_iterator it=vect.begin(); it!=vect.end(); it++)
- batch.Write(make_pair(DB_TXINDEX, it->first), it->second);
+ batch.Write(std::make_pair(DB_TXINDEX, it->first), it->second);
return WriteBatch(batch);
}
@@ -171,11 +259,11 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
return true;
}
-bool CBlockTreeDB::LoadBlockIndexGuts(boost::function<CBlockIndex*(const uint256&)> insertBlockIndex)
+bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function<CBlockIndex*(const uint256&)> insertBlockIndex)
{
std::unique_ptr<CDBIterator> pcursor(NewIterator());
- pcursor->Seek(make_pair(DB_BLOCK_INDEX, uint256()));
+ pcursor->Seek(std::make_pair(DB_BLOCK_INDEX, uint256()));
// Load mapBlockIndex
while (pcursor->Valid()) {
@@ -199,12 +287,12 @@ bool CBlockTreeDB::LoadBlockIndexGuts(boost::function<CBlockIndex*(const uint256
pindexNew->nStatus = diskindex.nStatus;
pindexNew->nTx = diskindex.nTx;
- if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, Params().GetConsensus()))
- return error("LoadBlockIndex(): CheckProofOfWork failed: %s", pindexNew->ToString());
+ if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, consensusParams))
+ return error("%s: CheckProofOfWork failed: %s", __func__, pindexNew->ToString());
pcursor->Next();
} else {
- return error("LoadBlockIndex() : failed to read value");
+ return error("%s: failed to read value", __func__);
}
} else {
break;
@@ -213,3 +301,126 @@ bool CBlockTreeDB::LoadBlockIndexGuts(boost::function<CBlockIndex*(const uint256
return true;
}
+
+namespace {
+
+//! Legacy class to deserialize pre-pertxout database entries without reindex.
+class CCoins
+{
+public:
+ //! whether transaction is a coinbase
+ bool fCoinBase;
+
+ //! unspent transaction outputs; spent outputs are .IsNull(); spent outputs at the end of the array are dropped
+ std::vector<CTxOut> vout;
+
+ //! at which height this transaction was included in the active block chain
+ int nHeight;
+
+ //! empty constructor
+ CCoins() : fCoinBase(false), vout(0), nHeight(0) { }
+
+ template<typename Stream>
+ void Unserialize(Stream &s) {
+ unsigned int nCode = 0;
+ // version
+ int nVersionDummy;
+ ::Unserialize(s, VARINT(nVersionDummy));
+ // header code
+ ::Unserialize(s, VARINT(nCode));
+ fCoinBase = nCode & 1;
+ std::vector<bool> vAvail(2, false);
+ vAvail[0] = (nCode & 2) != 0;
+ vAvail[1] = (nCode & 4) != 0;
+ unsigned int nMaskCode = (nCode / 8) + ((nCode & 6) != 0 ? 0 : 1);
+ // spentness bitmask
+ while (nMaskCode > 0) {
+ unsigned char chAvail = 0;
+ ::Unserialize(s, chAvail);
+ for (unsigned int p = 0; p < 8; p++) {
+ bool f = (chAvail & (1 << p)) != 0;
+ vAvail.push_back(f);
+ }
+ if (chAvail != 0)
+ nMaskCode--;
+ }
+ // txouts themself
+ vout.assign(vAvail.size(), CTxOut());
+ for (unsigned int i = 0; i < vAvail.size(); i++) {
+ if (vAvail[i])
+ ::Unserialize(s, REF(CTxOutCompressor(vout[i])));
+ }
+ // coinbase height
+ ::Unserialize(s, VARINT(nHeight));
+ }
+};
+
+}
+
+/** Upgrade the database from older formats.
+ *
+ * Currently implemented: from the per-tx utxo model (0.8..0.14.x) to per-txout.
+ */
+bool CCoinsViewDB::Upgrade() {
+ std::unique_ptr<CDBIterator> pcursor(db.NewIterator());
+ pcursor->Seek(std::make_pair(DB_COINS, uint256()));
+ if (!pcursor->Valid()) {
+ return true;
+ }
+
+ int64_t count = 0;
+ LogPrintf("Upgrading utxo-set database...\n");
+ LogPrintf("[0%%]...");
+ uiInterface.ShowProgress(_("Upgrading UTXO database"), 0, true);
+ size_t batch_size = 1 << 24;
+ CDBBatch batch(db);
+ int reportDone = 0;
+ std::pair<unsigned char, uint256> key;
+ std::pair<unsigned char, uint256> prev_key = {DB_COINS, uint256()};
+ while (pcursor->Valid()) {
+ boost::this_thread::interruption_point();
+ if (ShutdownRequested()) {
+ break;
+ }
+ if (pcursor->GetKey(key) && key.first == DB_COINS) {
+ if (count++ % 256 == 0) {
+ uint32_t high = 0x100 * *key.second.begin() + *(key.second.begin() + 1);
+ int percentageDone = (int)(high * 100.0 / 65536.0 + 0.5);
+ uiInterface.ShowProgress(_("Upgrading UTXO database"), percentageDone, true);
+ if (reportDone < percentageDone/10) {
+ // report max. every 10% step
+ LogPrintf("[%d%%]...", percentageDone);
+ reportDone = percentageDone/10;
+ }
+ }
+ CCoins old_coins;
+ if (!pcursor->GetValue(old_coins)) {
+ return error("%s: cannot parse CCoins record", __func__);
+ }
+ COutPoint outpoint(key.second, 0);
+ for (size_t i = 0; i < old_coins.vout.size(); ++i) {
+ if (!old_coins.vout[i].IsNull() && !old_coins.vout[i].scriptPubKey.IsUnspendable()) {
+ Coin newcoin(std::move(old_coins.vout[i]), old_coins.nHeight, old_coins.fCoinBase);
+ outpoint.n = i;
+ CoinEntry entry(&outpoint);
+ batch.Write(entry, newcoin);
+ }
+ }
+ batch.Erase(key);
+ if (batch.SizeEstimate() > batch_size) {
+ db.WriteBatch(batch);
+ batch.Clear();
+ db.CompactRange(prev_key, key);
+ prev_key = key;
+ }
+ pcursor->Next();
+ } else {
+ break;
+ }
+ }
+ db.WriteBatch(batch);
+ db.CompactRange({DB_COINS, uint256()}, key);
+ uiInterface.ShowProgress("", 100, false);
+ LogPrintf("[%s].\n", ShutdownRequested() ? "CANCELLED" : "DONE");
+ return !ShutdownRequested();
+}
diff --git a/src/txdb.h b/src/txdb.h
index 7f5cf2b583..ec9f571b13 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -15,14 +15,16 @@
#include <utility>
#include <vector>
-#include <boost/function.hpp>
-
class CBlockIndex;
class CCoinsViewDBCursor;
class uint256;
+//! No need to periodic flush if at least this much space still available.
+static constexpr int MAX_BLOCK_COINSDB_USAGE = 10;
//! -dbcache default (MiB)
-static const int64_t nDefaultDbCache = 300;
+static const int64_t nDefaultDbCache = 450;
+//! -dbbatchsize default (bytes)
+static const int64_t nDefaultDbBatchSize = 16 << 20;
//! max. -dbcache (MiB)
static const int64_t nMaxDbCache = sizeof(void*) > 4 ? 16384 : 1024;
//! min. -dbcache (MiB)
@@ -62,18 +64,23 @@ struct CDiskTxPos : public CDiskBlockPos
};
/** CCoinsView backed by the coin database (chainstate/) */
-class CCoinsViewDB : public CCoinsView
+class CCoinsViewDB final : public CCoinsView
{
protected:
CDBWrapper db;
public:
- CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
-
- bool GetCoins(const uint256 &txid, CCoins &coins) const;
- bool HaveCoins(const uint256 &txid) const;
- uint256 GetBestBlock() const;
- bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
- CCoinsViewCursor *Cursor() const;
+ explicit CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
+
+ bool GetCoin(const COutPoint &outpoint, Coin &coin) const override;
+ bool HaveCoin(const COutPoint &outpoint) const override;
+ uint256 GetBestBlock() const override;
+ std::vector<uint256> GetHeadBlocks() const override;
+ bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override;
+ CCoinsViewCursor *Cursor() const override;
+
+ //! Attempt to update from an older database format. Returns whether an error occurred.
+ bool Upgrade();
+ size_t EstimateSize() const override;
};
/** Specialization of CCoinsViewCursor to iterate over a CCoinsViewDB */
@@ -82,18 +89,18 @@ class CCoinsViewDBCursor: public CCoinsViewCursor
public:
~CCoinsViewDBCursor() {}
- bool GetKey(uint256 &key) const;
- bool GetValue(CCoins &coins) const;
- unsigned int GetValueSize() const;
+ bool GetKey(COutPoint &key) const override;
+ bool GetValue(Coin &coin) const override;
+ unsigned int GetValueSize() const override;
- bool Valid() const;
- void Next();
+ bool Valid() const override;
+ void Next() override;
private:
CCoinsViewDBCursor(CDBIterator* pcursorIn, const uint256 &hashBlockIn):
CCoinsViewCursor(hashBlockIn), pcursor(pcursorIn) {}
std::unique_ptr<CDBIterator> pcursor;
- std::pair<char, uint256> keyTmp;
+ std::pair<char, COutPoint> keyTmp;
friend class CCoinsViewDB;
};
@@ -102,21 +109,21 @@ private:
class CBlockTreeDB : public CDBWrapper
{
public:
- CBlockTreeDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
-private:
- CBlockTreeDB(const CBlockTreeDB&);
- void operator=(const CBlockTreeDB&);
-public:
+ explicit CBlockTreeDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
+
+ CBlockTreeDB(const CBlockTreeDB&) = delete;
+ CBlockTreeDB& operator=(const CBlockTreeDB&) = delete;
+
bool WriteBatchSync(const std::vector<std::pair<int, const CBlockFileInfo*> >& fileInfo, int nLastFile, const std::vector<const CBlockIndex*>& blockinfo);
- bool ReadBlockFileInfo(int nFile, CBlockFileInfo &fileinfo);
+ bool ReadBlockFileInfo(int nFile, CBlockFileInfo &info);
bool ReadLastBlockFile(int &nFile);
- bool WriteReindexing(bool fReindex);
- bool ReadReindexing(bool &fReindex);
+ bool WriteReindexing(bool fReindexing);
+ bool ReadReindexing(bool &fReindexing);
bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos);
- bool WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> > &list);
+ bool WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> > &vect);
bool WriteFlag(const std::string &name, bool fValue);
bool ReadFlag(const std::string &name, bool &fValue);
- bool LoadBlockIndexGuts(boost::function<CBlockIndex*(const uint256&)> insertBlockIndex);
+ bool LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function<CBlockIndex*(const uint256&)> insertBlockIndex);
};
#endif // BITCOIN_TXDB_H
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 5b085f492d..776d3f36ca 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -5,38 +5,31 @@
#include "txmempool.h"
-#include "clientversion.h"
#include "consensus/consensus.h"
+#include "consensus/tx_verify.h"
#include "consensus/validation.h"
#include "validation.h"
#include "policy/policy.h"
#include "policy/fees.h"
+#include "reverse_iterator.h"
#include "streams.h"
#include "timedata.h"
#include "util.h"
#include "utilmoneystr.h"
#include "utiltime.h"
-#include "version.h"
-
-using namespace std;
CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,
- int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
- CAmount _inChainInputValue,
+ int64_t _nTime, unsigned int _entryHeight,
bool _spendsCoinbase, int64_t _sigOpsCost, LockPoints lp):
- tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight),
- inChainInputValue(_inChainInputValue),
+ tx(_tx), nFee(_nFee), nTime(_nTime), entryHeight(_entryHeight),
spendsCoinbase(_spendsCoinbase), sigOpCost(_sigOpsCost), lockPoints(lp)
{
nTxWeight = GetTransactionWeight(*tx);
- nModSize = tx->CalculateModifiedSize(GetTxSize());
- nUsageSize = RecursiveDynamicUsage(*tx) + memusage::DynamicUsage(tx);
+ nUsageSize = RecursiveDynamicUsage(tx);
nCountWithDescendants = 1;
nSizeWithDescendants = GetTxSize();
nModFeesWithDescendants = nFee;
- CAmount nValueIn = tx->GetValueOut()+nFee;
- assert(inChainInputValue <= nValueIn);
feeDelta = 0;
@@ -46,21 +39,6 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFe
nSigOpCostWithAncestors = sigOpCost;
}
-CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other)
-{
- *this = other;
-}
-
-double
-CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const
-{
- double deltaPriority = ((double)(currentHeight-entryHeight)*inChainInputValue)/nModSize;
- double dResult = entryPriority + deltaPriority;
- if (dResult < 0) // This should only happen if it was called with a height below entry height
- dResult = 0;
- return dResult;
-}
-
void CTxMemPoolEntry::UpdateFeeDelta(int64_t newFeeDelta)
{
nModFeesWithDescendants += newFeeDelta - feeDelta;
@@ -91,12 +69,12 @@ void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendan
setAllDescendants.insert(cit);
stageEntries.erase(cit);
const setEntries &setChildren = GetMemPoolChildren(cit);
- BOOST_FOREACH(const txiter childEntry, setChildren) {
+ for (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) {
+ for (const txiter cacheEntry : cacheIt->second) {
setAllDescendants.insert(cacheEntry);
}
} else if (!setAllDescendants.count(childEntry)) {
@@ -110,7 +88,7 @@ void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendan
int64_t modifySize = 0;
CAmount modifyFee = 0;
int64_t modifyCount = 0;
- BOOST_FOREACH(txiter cit, setAllDescendants) {
+ for (txiter cit : setAllDescendants) {
if (!setExclude.count(cit->GetTx().GetHash())) {
modifySize += cit->GetTxSize();
modifyFee += cit->GetModifiedFee();
@@ -125,7 +103,7 @@ void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendan
// 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
+// for each entry, look for descendants that are outside vHashesToUpdate, and
// add fee/size information for such descendants to the parent.
// for each such descendant, also update the ancestor state to include the parent.
void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256> &vHashesToUpdate)
@@ -140,12 +118,12 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256> &vHashes
// 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
+ // Iterate in reverse, so that whenever we are looking 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) {
+ for (const uint256 &hash : reverse_iterate(vHashesToUpdate)) {
// we cache the in-mempool children to avoid duplicate updates
setEntries setChildren;
// calculate children from mapNextTx
@@ -173,6 +151,8 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256> &vHashes
bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents /* = true */) const
{
+ LOCK(cs);
+
setEntries parentHashes;
const CTransaction &tx = entry.GetTx();
@@ -218,7 +198,7 @@ bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntr
}
const setEntries & setMemPoolParents = GetMemPoolParents(stageit);
- BOOST_FOREACH(const txiter &phash, setMemPoolParents) {
+ for (const txiter &phash : setMemPoolParents) {
// If this is a new ancestor, add it.
if (setAncestors.count(phash) == 0) {
parentHashes.insert(phash);
@@ -237,13 +217,13 @@ 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) {
+ for (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->GetModifiedFee();
- BOOST_FOREACH(txiter ancestorIt, setAncestors) {
+ for (txiter ancestorIt : setAncestors) {
mapTx.modify(ancestorIt, update_descendant_state(updateSize, updateFee, updateCount));
}
}
@@ -254,7 +234,7 @@ void CTxMemPool::UpdateEntryForAncestors(txiter it, const setEntries &setAncesto
int64_t updateSize = 0;
CAmount updateFee = 0;
int64_t updateSigOpsCost = 0;
- BOOST_FOREACH(txiter ancestorIt, setAncestors) {
+ for (txiter ancestorIt : setAncestors) {
updateSize += ancestorIt->GetTxSize();
updateFee += ancestorIt->GetModifiedFee();
updateSigOpsCost += ancestorIt->GetSigOpCost();
@@ -265,7 +245,7 @@ void CTxMemPool::UpdateEntryForAncestors(txiter it, const setEntries &setAncesto
void CTxMemPool::UpdateChildrenForRemoval(txiter it)
{
const setEntries &setMemPoolChildren = GetMemPoolChildren(it);
- BOOST_FOREACH(txiter updateIt, setMemPoolChildren) {
+ for (txiter updateIt : setMemPoolChildren) {
UpdateParent(updateIt, it, false);
}
}
@@ -282,19 +262,19 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, b
// Here we only update statistics and not data in mapLinks (which
// we need to preserve until we're finished with all operations that
// need to traverse the mempool).
- BOOST_FOREACH(txiter removeIt, entriesToRemove) {
+ for (txiter removeIt : entriesToRemove) {
setEntries setDescendants;
CalculateDescendants(removeIt, setDescendants);
setDescendants.erase(removeIt); // don't update state for self
int64_t modifySize = -((int64_t)removeIt->GetTxSize());
CAmount modifyFee = -removeIt->GetModifiedFee();
int modifySigOps = -removeIt->GetSigOpCost();
- BOOST_FOREACH(txiter dit, setDescendants) {
+ for (txiter dit : setDescendants) {
mapTx.modify(dit, update_ancestor_state(modifySize, modifyFee, -1, modifySigOps));
}
}
}
- BOOST_FOREACH(txiter removeIt, entriesToRemove) {
+ for (txiter removeIt : entriesToRemove) {
setEntries setAncestors;
const CTxMemPoolEntry &entry = *removeIt;
std::string dummy;
@@ -323,7 +303,7 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, b
// 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) {
+ for (txiter removeIt : entriesToRemove) {
UpdateChildrenForRemoval(removeIt);
}
}
@@ -348,8 +328,8 @@ void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee,
assert(int(nSigOpCostWithAncestors) >= 0);
}
-CTxMemPool::CTxMemPool(const CFeeRate& _minReasonableRelayFee) :
- nTransactionsUpdated(0)
+CTxMemPool::CTxMemPool(CBlockPolicyEstimator* estimator) :
+ nTransactionsUpdated(0), minerPolicyEstimator(estimator)
{
_clear(); //lock free clear
@@ -357,26 +337,12 @@ CTxMemPool::CTxMemPool(const CFeeRate& _minReasonableRelayFee) :
// accepting transactions becomes O(N^2) where N is the number
// of transactions in the pool
nCheckFrequency = 0;
-
- minerPolicyEstimator = new CBlockPolicyEstimator(_minReasonableRelayFee);
}
-CTxMemPool::~CTxMemPool()
-{
- delete minerPolicyEstimator;
-}
-
-void CTxMemPool::pruneSpent(const uint256 &hashTx, CCoins &coins)
+bool CTxMemPool::isSpent(const COutPoint& outpoint)
{
LOCK(cs);
-
- auto it = mapNextTx.lower_bound(COutPoint(hashTx, 0));
-
- // iterate over all COutPoints in mapNextTx whose hash equals the provided hashTx
- while (it != mapNextTx.end() && it->first->hash == hashTx) {
- coins.Spend(it->first->n); // and remove those outputs from coins
- it++;
- }
+ return mapNextTx.count(outpoint);
}
unsigned int CTxMemPool::GetTransactionsUpdated() const
@@ -393,8 +359,9 @@ void CTxMemPool::AddTransactionsUpdated(unsigned int n)
bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool validFeeEstimate)
{
+ NotifyEntryAdded(entry.GetSharedTx());
// Add to memory pool without checking anything.
- // Used by main.cpp AcceptToMemoryPool(), which DOES do
+ // Used by AcceptToMemoryPool(), which DOES do
// all the appropriate checks.
LOCK(cs);
indexed_transaction_set::iterator newit = mapTx.insert(entry).first;
@@ -403,11 +370,11 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
// Update transaction for any feeDelta created by PrioritiseTransaction
// TODO: refactor so that the fee delta is calculated before inserting
// into mapTx.
- std::map<uint256, std::pair<double, CAmount> >::const_iterator pos = mapDeltas.find(hash);
+ std::map<uint256, CAmount>::const_iterator pos = mapDeltas.find(hash);
if (pos != mapDeltas.end()) {
- const std::pair<double, CAmount> &deltas = pos->second;
- if (deltas.second) {
- mapTx.modify(newit, update_fee_delta(deltas.second));
+ const CAmount &delta = pos->second;
+ if (delta) {
+ mapTx.modify(newit, update_fee_delta(delta));
}
}
@@ -430,7 +397,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
// to clean up the mess we're leaving here.
// Update ancestors with information about this tx
- BOOST_FOREACH (const uint256 &phash, setParentTransactions) {
+ for (const uint256 &phash : setParentTransactions) {
txiter pit = mapTx.find(phash);
if (pit != mapTx.end()) {
UpdateParent(newit, pit, true);
@@ -441,7 +408,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
nTransactionsUpdated++;
totalTxSize += entry.GetTxSize();
- minerPolicyEstimator->processTransaction(entry, validFeeEstimate);
+ if (minerPolicyEstimator) {minerPolicyEstimator->processTransaction(entry, validFeeEstimate);}
vTxHashes.emplace_back(tx.GetWitnessHash(), newit);
newit->vTxHashesIdx = vTxHashes.size() - 1;
@@ -449,10 +416,11 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
return true;
}
-void CTxMemPool::removeUnchecked(txiter it)
+void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason)
{
+ NotifyEntryRemoved(it->GetSharedTx(), reason);
const uint256 hash = it->GetTx().GetHash();
- BOOST_FOREACH(const CTxIn& txin, it->GetTx().vin)
+ for (const CTxIn& txin : it->GetTx().vin)
mapNextTx.erase(txin.prevout);
if (vTxHashes.size() > 1) {
@@ -470,7 +438,7 @@ void CTxMemPool::removeUnchecked(txiter it)
mapLinks.erase(it);
mapTx.erase(it);
nTransactionsUpdated++;
- minerPolicyEstimator->removeTx(hash);
+ if (minerPolicyEstimator) {minerPolicyEstimator->removeTx(hash, false);}
}
// Calculates descendants of entry that are not already in setDescendants, and adds to
@@ -494,7 +462,7 @@ void CTxMemPool::CalculateDescendants(txiter entryit, setEntries &setDescendants
stage.erase(it);
const setEntries &setChildren = GetMemPoolChildren(it);
- BOOST_FOREACH(const txiter &childiter, setChildren) {
+ for (const txiter &childiter : setChildren) {
if (!setDescendants.count(childiter)) {
stage.insert(childiter);
}
@@ -502,7 +470,7 @@ void CTxMemPool::CalculateDescendants(txiter entryit, setEntries &setDescendants
}
}
-void CTxMemPool::removeRecursive(const CTransaction &origTx)
+void CTxMemPool::removeRecursive(const CTransaction &origTx, MemPoolRemovalReason reason)
{
// Remove transaction from memory pool
{
@@ -526,10 +494,11 @@ void CTxMemPool::removeRecursive(const CTransaction &origTx)
}
}
setEntries setAllRemoves;
- BOOST_FOREACH(txiter it, txToRemove) {
+ for (txiter it : txToRemove) {
CalculateDescendants(it, setAllRemoves);
}
- RemoveStaged(setAllRemoves, false);
+
+ RemoveStaged(setAllRemoves, false, reason);
}
}
@@ -547,13 +516,13 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem
// So it's critical that we remove the tx and not depend on the LockPoints.
txToRemove.insert(it);
} else if (it->GetSpendsCoinbase()) {
- BOOST_FOREACH(const CTxIn& txin, tx.vin) {
+ for (const CTxIn& txin : tx.vin) {
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 (nCheckFrequency != 0) assert(coins);
- if (!coins || (coins->IsCoinBase() && ((signed long)nMemPoolHeight) - coins->nHeight < COINBASE_MATURITY)) {
+ const Coin &coin = pcoins->AccessCoin(txin.prevout);
+ if (nCheckFrequency != 0) assert(!coin.IsSpent());
+ if (coin.IsSpent() || (coin.IsCoinBase() && ((signed long)nMemPoolHeight) - coin.nHeight < COINBASE_MATURITY)) {
txToRemove.insert(it);
break;
}
@@ -567,21 +536,21 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem
for (txiter it : txToRemove) {
CalculateDescendants(it, setAllRemoves);
}
- RemoveStaged(setAllRemoves, false);
+ RemoveStaged(setAllRemoves, false, MemPoolRemovalReason::REORG);
}
void CTxMemPool::removeConflicts(const CTransaction &tx)
{
// Remove transactions which depend on inputs of tx, recursively
LOCK(cs);
- BOOST_FOREACH(const CTxIn &txin, tx.vin) {
+ for (const CTxIn &txin : tx.vin) {
auto it = mapNextTx.find(txin.prevout);
if (it != mapNextTx.end()) {
const CTransaction &txConflict = *it->second;
if (txConflict != tx)
{
ClearPrioritisation(txConflict.GetHash());
- removeRecursive(txConflict);
+ removeRecursive(txConflict, MemPoolRemovalReason::CONFLICT);
}
}
}
@@ -603,14 +572,14 @@ void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigne
entries.push_back(&*i);
}
// Before the txs in the new block have been removed from the mempool, update policy estimates
- minerPolicyEstimator->processBlock(nBlockHeight, entries);
+ if (minerPolicyEstimator) {minerPolicyEstimator->processBlock(nBlockHeight, entries);}
for (const auto& tx : vtx)
{
txiter it = mapTx.find(tx->GetHash());
if (it != mapTx.end()) {
setEntries stage;
stage.insert(it);
- RemoveStaged(stage, true);
+ RemoveStaged(stage, true, MemPoolRemovalReason::BLOCK);
}
removeConflicts(*tx);
ClearPrioritisation(tx->GetHash());
@@ -646,7 +615,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
if (GetRand(std::numeric_limits<uint32_t>::max()) >= nCheckFrequency)
return;
- LogPrint("mempool", "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size());
+ LogPrint(BCLog::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;
@@ -655,7 +624,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
const int64_t nSpendHeight = GetSpendHeight(mempoolDuplicate);
LOCK(cs);
- list<const CTxMemPoolEntry*> waitingOnDependants;
+ std::list<const CTxMemPoolEntry*> waitingOnDependants;
for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
unsigned int i = 0;
checkTotal += it->GetTxSize();
@@ -669,7 +638,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
setEntries setParentCheck;
int64_t parentSizes = 0;
int64_t parentSigOpCost = 0;
- BOOST_FOREACH(const CTxIn &txin, tx.vin) {
+ for (const CTxIn &txin : tx.vin) {
// Check that every mempool transaction's inputs refer to available coins, or other mempool tx's.
indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash);
if (it2 != mapTx.end()) {
@@ -681,8 +650,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
parentSigOpCost += it2->GetSigOpCost();
}
} else {
- const CCoins* coins = pcoins->AccessCoins(txin.prevout.hash);
- assert(coins && coins->IsAvailable(txin.prevout.n));
+ assert(pcoins->HaveCoin(txin.prevout));
}
// Check whether its inputs are marked in mapNextTx.
auto it3 = mapNextTx.find(txin.prevout);
@@ -702,7 +670,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
CAmount nFeesCheck = it->GetModifiedFee();
int64_t nSigOpCheck = it->GetSigOpCost();
- BOOST_FOREACH(txiter ancestorIt, setAncestors) {
+ for (txiter ancestorIt : setAncestors) {
nSizeCheck += ancestorIt->GetTxSize();
nFeesCheck += ancestorIt->GetModifiedFee();
nSigOpCheck += ancestorIt->GetSigOpCost();
@@ -797,7 +765,7 @@ public:
return counta < countb;
}
};
-}
+} // namespace
std::vector<CTxMemPool::indexed_transaction_set::const_iterator> CTxMemPool::GetSortedDepthAndScore() const
{
@@ -813,7 +781,7 @@ std::vector<CTxMemPool::indexed_transaction_set::const_iterator> CTxMemPool::Get
return iters;
}
-void CTxMemPool::queryHashes(vector<uint256>& vtxid)
+void CTxMemPool::queryHashes(std::vector<uint256>& vtxid)
{
LOCK(cs);
auto iters = GetSortedDepthAndScore();
@@ -862,93 +830,44 @@ TxMempoolInfo CTxMemPool::info(const uint256& hash) const
return GetInfo(i);
}
-CFeeRate CTxMemPool::estimateFee(int nBlocks) const
-{
- LOCK(cs);
- return minerPolicyEstimator->estimateFee(nBlocks);
-}
-CFeeRate CTxMemPool::estimateSmartFee(int nBlocks, int *answerFoundAtBlocks) const
-{
- LOCK(cs);
- return minerPolicyEstimator->estimateSmartFee(nBlocks, answerFoundAtBlocks, *this);
-}
-double CTxMemPool::estimatePriority(int nBlocks) const
-{
- LOCK(cs);
- return minerPolicyEstimator->estimatePriority(nBlocks);
-}
-double CTxMemPool::estimateSmartPriority(int nBlocks, int *answerFoundAtBlocks) const
-{
- LOCK(cs);
- return minerPolicyEstimator->estimateSmartPriority(nBlocks, answerFoundAtBlocks, *this);
-}
-
-bool
-CTxMemPool::WriteFeeEstimates(CAutoFile& fileout) const
-{
- try {
- LOCK(cs);
- fileout << 139900; // version required to read: 0.13.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)\n");
- return false;
- }
- return true;
-}
-
-bool
-CTxMemPool::ReadFeeEstimates(CAutoFile& filein)
-{
- try {
- int nVersionRequired, nVersionThatWrote;
- filein >> nVersionRequired >> nVersionThatWrote;
- if (nVersionRequired > CLIENT_VERSION)
- return error("CTxMemPool::ReadFeeEstimates(): up-version (%d) fee estimate file", nVersionRequired);
- LOCK(cs);
- minerPolicyEstimator->Read(filein, nVersionThatWrote);
- }
- catch (const std::exception&) {
- LogPrintf("CTxMemPool::ReadFeeEstimates(): unable to read policy estimator data (non-fatal)\n");
- return false;
- }
- return true;
-}
-
-void CTxMemPool::PrioritiseTransaction(const uint256 hash, const string strHash, double dPriorityDelta, const CAmount& nFeeDelta)
+void CTxMemPool::PrioritiseTransaction(const uint256& hash, const CAmount& nFeeDelta)
{
{
LOCK(cs);
- std::pair<double, CAmount> &deltas = mapDeltas[hash];
- deltas.first += dPriorityDelta;
- deltas.second += nFeeDelta;
+ CAmount &delta = mapDeltas[hash];
+ delta += nFeeDelta;
txiter it = mapTx.find(hash);
if (it != mapTx.end()) {
- mapTx.modify(it, update_fee_delta(deltas.second));
+ mapTx.modify(it, update_fee_delta(delta));
// Now update all ancestors' modified fees with descendants
setEntries setAncestors;
uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
std::string dummy;
CalculateMemPoolAncestors(*it, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false);
- BOOST_FOREACH(txiter ancestorIt, setAncestors) {
+ for (txiter ancestorIt : setAncestors) {
mapTx.modify(ancestorIt, update_descendant_state(0, nFeeDelta, 0));
}
+ // Now update all descendants' modified fees with ancestors
+ setEntries setDescendants;
+ CalculateDescendants(it, setDescendants);
+ setDescendants.erase(it);
+ for (txiter descendantIt : setDescendants) {
+ mapTx.modify(descendantIt, update_ancestor_state(0, nFeeDelta, 0, 0));
+ }
+ ++nTransactionsUpdated;
}
}
- LogPrintf("PrioritiseTransaction: %s priority += %f, fee += %d\n", strHash, dPriorityDelta, FormatMoney(nFeeDelta));
+ LogPrintf("PrioritiseTransaction: %s feerate += %s\n", hash.ToString(), FormatMoney(nFeeDelta));
}
-void CTxMemPool::ApplyDeltas(const uint256 hash, double &dPriorityDelta, CAmount &nFeeDelta) const
+void CTxMemPool::ApplyDelta(const uint256 hash, CAmount &nFeeDelta) const
{
LOCK(cs);
- std::map<uint256, std::pair<double, CAmount> >::const_iterator pos = mapDeltas.find(hash);
+ std::map<uint256, CAmount>::const_iterator pos = mapDeltas.find(hash);
if (pos == mapDeltas.end())
return;
- const std::pair<double, CAmount> &deltas = pos->second;
- dPriorityDelta += deltas.first;
- nFeeDelta += deltas.second;
+ const CAmount &delta = pos->second;
+ nFeeDelta += delta;
}
void CTxMemPool::ClearPrioritisation(const uint256 hash)
@@ -967,20 +886,20 @@ bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const
CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView* baseIn, const CTxMemPool& mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
-bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) const {
+bool CCoinsViewMemPool::GetCoin(const COutPoint &outpoint, Coin &coin) const {
// If an entry in the mempool exists, always return that one, as it's guaranteed to never
// conflict with the underlying cache, and it cannot have pruned entries (as it contains full)
// transactions. First checking the underlying cache risks returning a pruned entry instead.
- CTransactionRef ptx = mempool.get(txid);
+ CTransactionRef ptx = mempool.get(outpoint.hash);
if (ptx) {
- coins = CCoins(*ptx, MEMPOOL_HEIGHT);
- return true;
+ if (outpoint.n < ptx->vout.size()) {
+ coin = Coin(ptx->vout[outpoint.n], MEMPOOL_HEIGHT, false);
+ return true;
+ } else {
+ return false;
+ }
}
- return (base->GetCoins(txid, coins) && !coins.IsPruned());
-}
-
-bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) const {
- return mempool.exists(txid) || base->HaveCoins(txid);
+ return base->GetCoin(outpoint, coin);
}
size_t CTxMemPool::DynamicMemoryUsage() const {
@@ -989,11 +908,11 @@ size_t CTxMemPool::DynamicMemoryUsage() const {
return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 15 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapLinks) + memusage::DynamicUsage(vTxHashes) + cachedInnerUsage;
}
-void CTxMemPool::RemoveStaged(setEntries &stage, bool updateDescendants) {
+void CTxMemPool::RemoveStaged(setEntries &stage, bool updateDescendants, MemPoolRemovalReason reason) {
AssertLockHeld(cs);
UpdateForRemoveFromMempool(stage, updateDescendants);
- BOOST_FOREACH(const txiter& it, stage) {
- removeUnchecked(it);
+ for (const txiter& it : stage) {
+ removeUnchecked(it, reason);
}
}
@@ -1006,10 +925,10 @@ int CTxMemPool::Expire(int64_t time) {
it++;
}
setEntries stage;
- BOOST_FOREACH(txiter removeit, toremove) {
+ for (txiter removeit : toremove) {
CalculateDescendants(removeit, stage);
}
- RemoveStaged(stage, false);
+ RemoveStaged(stage, false, MemPoolRemovalReason::EXPIRY);
return stage.size();
}
@@ -1062,7 +981,7 @@ const CTxMemPool::setEntries & CTxMemPool::GetMemPoolChildren(txiter entry) cons
CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const {
LOCK(cs);
if (!blockSinceLastRollingFeeBump || rollingMinimumFeeRate == 0)
- return CFeeRate(rollingMinimumFeeRate);
+ return CFeeRate(llround(rollingMinimumFeeRate));
int64_t time = GetTime();
if (time > lastRollingFeeUpdate + 10) {
@@ -1080,7 +999,7 @@ CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const {
return CFeeRate(0);
}
}
- return std::max(CFeeRate(rollingMinimumFeeRate), incrementalRelayFee);
+ return std::max(CFeeRate(llround(rollingMinimumFeeRate)), incrementalRelayFee);
}
void CTxMemPool::trackPackageRemoved(const CFeeRate& rate) {
@@ -1091,7 +1010,7 @@ void CTxMemPool::trackPackageRemoved(const CFeeRate& rate) {
}
}
-void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<uint256>* pvNoSpendsRemaining) {
+void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpendsRemaining) {
LOCK(cs);
unsigned nTxnRemoved = 0;
@@ -1115,25 +1034,23 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<uint256>* pvNoSpendsRe
std::vector<CTransaction> txn;
if (pvNoSpendsRemaining) {
txn.reserve(stage.size());
- BOOST_FOREACH(txiter iter, stage)
+ for (txiter iter : stage)
txn.push_back(iter->GetTx());
}
- RemoveStaged(stage, false);
+ RemoveStaged(stage, false, MemPoolRemovalReason::SIZELIMIT);
if (pvNoSpendsRemaining) {
- BOOST_FOREACH(const CTransaction& tx, txn) {
- BOOST_FOREACH(const CTxIn& txin, tx.vin) {
- if (exists(txin.prevout.hash))
- continue;
- auto iter = mapNextTx.lower_bound(COutPoint(txin.prevout.hash, 0));
- if (iter == mapNextTx.end() || iter->first->hash != txin.prevout.hash)
- pvNoSpendsRemaining->push_back(txin.prevout.hash);
+ for (const CTransaction& tx : txn) {
+ for (const CTxIn& txin : tx.vin) {
+ if (exists(txin.prevout.hash)) continue;
+ pvNoSpendsRemaining->push_back(txin.prevout);
}
}
}
}
- if (maxFeeRateRemoved > CFeeRate(0))
- LogPrint("mempool", "Removed %u txn, rolling minimum fee bumped to %s\n", nTxnRemoved, maxFeeRateRemoved.ToString());
+ if (maxFeeRateRemoved > CFeeRate(0)) {
+ LogPrint(BCLog::MEMPOOL, "Removed %u txn, rolling minimum fee bumped to %s\n", nTxnRemoved, maxFeeRateRemoved.ToString());
+ }
}
bool CTxMemPool::TransactionWithinChainLimit(const uint256& txid, size_t chainLimit) const {
@@ -1142,3 +1059,5 @@ bool CTxMemPool::TransactionWithinChainLimit(const uint256& txid, size_t chainLi
return it == mapTx.end() || (it->GetCountWithAncestors() < chainLimit &&
it->GetCountWithDescendants() < chainLimit);
}
+
+SaltedTxidHasher::SaltedTxidHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
diff --git a/src/txmempool.h b/src/txmempool.h
index ffb1c1309b..929d223588 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -16,32 +16,21 @@
#include "amount.h"
#include "coins.h"
#include "indirectmap.h"
+#include "policy/feerate.h"
#include "primitives/transaction.h"
#include "sync.h"
#include "random.h"
-#undef foreach
-#include "boost/multi_index_container.hpp"
-#include "boost/multi_index/ordered_index.hpp"
-#include "boost/multi_index/hashed_index.hpp"
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/sequenced_index.hpp>
+#include <boost/signals2/signal.hpp>
-class CAutoFile;
class CBlockIndex;
-inline double AllowFreeThreshold()
-{
- return COIN * 144 / 250;
-}
-
-inline bool AllowFree(double dPriority)
-{
- // Large (in bytes) low-priority (new, small-coin) transactions
- // need a fee.
- return dPriority > AllowFreeThreshold();
-}
-
-/** 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;
+/** Fake height value used in Coin to signify they are only in the memory pool (since 0.8) */
+static const uint32_t MEMPOOL_HEIGHT = 0x7FFFFFFF;
struct LockPoints
{
@@ -55,7 +44,7 @@ struct LockPoints
// values are still valid even after a reorg.
CBlockIndex* maxInputBlock;
- LockPoints() : height(0), time(0), maxInputBlock(NULL) { }
+ LockPoints() : height(0), time(0), maxInputBlock(nullptr) { }
};
class CTxMemPool;
@@ -70,11 +59,6 @@ class CTxMemPool;
* (nCountWithDescendants, nSizeWithDescendants, and nModFeesWithDescendants) 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/nModFeesWithDescendants to equal nTxSize/
- * nFee+feeDelta. (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
@@ -83,12 +67,9 @@ private:
CTransactionRef tx;
CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups
size_t nTxWeight; //!< ... and avoid recomputing tx weight (also used for GetTxSize())
- size_t nModSize; //!< ... and modified size for priority
size_t nUsageSize; //!< ... and total memory usage
int64_t nTime; //!< Local time when entering the mempool
- double entryPriority; //!< Priority when entering the mempool
unsigned int entryHeight; //!< Chain height when entering the mempool
- CAmount inChainInputValue; //!< Sum of all txin values that are already in blockchain
bool spendsCoinbase; //!< keep track of transactions that spend a coinbase
int64_t sigOpCost; //!< Total sigop cost
int64_t feeDelta; //!< Used for determining the priority of the transaction for mining in a block
@@ -96,9 +77,7 @@ private:
// 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 nModFeesWithDescendants will not be
- // correct.
+ // descendants as well.
uint64_t nCountWithDescendants; //!< number of descendant transactions
uint64_t nSizeWithDescendants; //!< ... and size
CAmount nModFeesWithDescendants; //!< ... and total fees (all including us)
@@ -111,19 +90,12 @@ private:
public:
CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,
- int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
- CAmount _inChainInputValue, bool spendsCoinbase,
+ int64_t _nTime, unsigned int _entryHeight,
+ bool spendsCoinbase,
int64_t nSigOpsCost, LockPoints lp);
- CTxMemPoolEntry(const CTxMemPoolEntry& other);
-
const CTransaction& GetTx() const { return *this->tx; }
CTransactionRef GetSharedTx() const { return this->tx; }
- /**
- * Fast calculation of lower bound of current priority as update
- * from entry priority. Only inputs that were originally in-chain will age.
- */
- double GetPriority(unsigned int currentHeight) const;
const CAmount& GetFee() const { return nFee; }
size_t GetTxSize() const;
size_t GetTxWeight() const { return nTxWeight; }
@@ -134,7 +106,7 @@ public:
size_t DynamicMemoryUsage() const { return nUsageSize; }
const LockPoints& GetLockPoints() const { return lockPoints; }
- // Adjusts the descendant state, if this entry is not dirty.
+ // Adjusts the descendant state.
void UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount);
// Adjusts the ancestor state
void UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int modifySigOps);
@@ -192,7 +164,7 @@ struct update_ancestor_state
struct update_fee_delta
{
- update_fee_delta(int64_t _feeDelta) : feeDelta(_feeDelta) { }
+ explicit update_fee_delta(int64_t _feeDelta) : feeDelta(_feeDelta) { }
void operator() (CTxMemPoolEntry &e) { e.UpdateFeeDelta(feeDelta); }
@@ -202,7 +174,7 @@ private:
struct update_lock_points
{
- update_lock_points(const LockPoints& _lp) : lp(_lp) { }
+ explicit update_lock_points(const LockPoints& _lp) : lp(_lp) { }
void operator() (CTxMemPoolEntry &e) { e.UpdateLockPoints(lp); }
@@ -210,7 +182,7 @@ private:
const LockPoints& lp;
};
-// extracts a TxMemPoolEntry's transaction hash
+// extracts a transaction hash from CTxMempoolEntry or CTransactionRef
struct mempoolentry_txid
{
typedef uint256 result_type;
@@ -218,6 +190,11 @@ struct mempoolentry_txid
{
return entry.GetTx().GetHash();
}
+
+ result_type operator() (const CTransactionRef& tx) const
+ {
+ return tx->GetHash();
+ }
};
/** \class CompareTxMemPoolEntryByDescendantScore
@@ -333,6 +310,33 @@ struct TxMempoolInfo
int64_t nFeeDelta;
};
+/** Reason why a transaction was removed from the mempool,
+ * this is passed to the notification signal.
+ */
+enum class MemPoolRemovalReason {
+ UNKNOWN = 0, //! Manually removed or unknown reason
+ EXPIRY, //! Expired from mempool
+ SIZELIMIT, //! Removed in size limiting
+ REORG, //! Removed for reorganization
+ BLOCK, //! Removed for block
+ CONFLICT, //! Removed for conflict with in-block transaction
+ REPLACED //! Removed for replacement
+};
+
+class SaltedTxidHasher
+{
+private:
+ /** Salt */
+ const uint64_t k0, k1;
+
+public:
+ SaltedTxidHasher();
+
+ size_t operator()(const uint256& txid) const {
+ return SipHashUint256(k0, k1, txid);
+ }
+};
+
/**
* CTxMemPool stores valid-according-to-the-current-best-chain transactions
* that may be included in the next block.
@@ -340,7 +344,7 @@ struct TxMempoolInfo
* Transactions are added when they are seen on the network (or created by the
* local node), but not all transactions seen are added to the pool. For
* example, the following new transactions will not be added to the mempool:
- * - a transaction which doesn't make the mimimum fee requirements.
+ * - a transaction which doesn't meet the minimum fee requirements.
* - a new transaction that double-spends an input of a transaction already in
* the pool where the new transaction does not meet the Replace-By-Fee
* requirements as defined in BIP 125.
@@ -404,20 +408,12 @@ struct TxMempoolInfo
* 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:
uint32_t nCheckFrequency; //!< Value n means that n times in 2^32 we check.
- unsigned int nTransactionsUpdated;
+ unsigned int nTransactionsUpdated; //!< Used by getblocktemplate to trigger CreateNewBlock() invocation
CBlockPolicyEstimator* minerPolicyEstimator;
uint64_t totalTxSize; //!< sum of all mempool tx's virtual sizes. Differs from serialized tx size since witness data is discounted. Defined in BIP 141.
@@ -498,12 +494,11 @@ private:
public:
indirectmap<COutPoint, const CTransaction*> mapNextTx;
- std::map<uint256, std::pair<double, CAmount> > mapDeltas;
+ std::map<uint256, CAmount> mapDeltas;
/** Create a new CTxMemPool.
*/
- CTxMemPool(const CFeeRate& _minReasonableRelayFee);
- ~CTxMemPool();
+ explicit CTxMemPool(CBlockPolicyEstimator* estimator = nullptr);
/**
* If sanity-checking is turned on, check makes sure the pool is
@@ -512,7 +507,7 @@ public:
* check does nothing.
*/
void check(const CCoinsViewCache *pcoins) const;
- void setSanityCheck(double dFrequency = 1.0) { nCheckFrequency = dFrequency * 4294967295.0; }
+ void setSanityCheck(double dFrequency = 1.0) { nCheckFrequency = static_cast<uint32_t>(dFrequency * 4294967295.0); }
// addUnchecked must updated state for all ancestors of a given transaction,
// to track size/count of descendant transactions. First version of
@@ -521,15 +516,16 @@ public:
bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, bool validFeeEstimate = true);
bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool validFeeEstimate = true);
- void removeRecursive(const CTransaction &tx);
+ void removeRecursive(const CTransaction &tx, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN);
void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags);
void removeConflicts(const CTransaction &tx);
void removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight);
+
void clear();
void _clear(); //lock free
bool CompareDepthAndScore(const uint256& hasha, const uint256& hashb);
void queryHashes(std::vector<uint256>& vtxid);
- void pruneSpent(const uint256& hash, CCoins &coins);
+ bool isSpent(const COutPoint& outpoint);
unsigned int GetTransactionsUpdated() const;
void AddTransactionsUpdated(unsigned int n);
/**
@@ -539,8 +535,8 @@ public:
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) const;
+ void PrioritiseTransaction(const uint256& hash, const CAmount& nFeeDelta);
+ void ApplyDelta(const uint256 hash, CAmount &nFeeDelta) const;
void ClearPrioritisation(const uint256 hash);
public:
@@ -551,18 +547,18 @@ public:
* Set updateDescendants to true when removing a tx that was in a block, so
* that any in-mempool descendants have their ancestor state updated.
*/
- void RemoveStaged(setEntries &stage, bool updateDescendants);
+ void RemoveStaged(setEntries &stage, bool updateDescendants, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN);
/** 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
+ * descendant state for each transaction in vHashesToUpdate (excluding any
+ * child transactions present in vHashesToUpdate, which are already accounted
+ * for). Note: vHashesToUpdate 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);
+ void UpdateTransactionsFromBlock(const std::vector<uint256> &vHashesToUpdate);
/** Try to calculate all in-mempool ancestors of entry.
* (these are all calculated including the tx itself)
@@ -590,10 +586,10 @@ public:
CFeeRate GetMinFee(size_t sizelimit) const;
/** Remove transactions from the mempool until its dynamic size is <= sizelimit.
- * pvNoSpendsRemaining, if set, will be populated with the list of transactions
+ * pvNoSpendsRemaining, if set, will be populated with the list of outpoints
* which are not in mempool which no longer have any spends in this mempool.
*/
- void TrimToSize(size_t sizelimit, std::vector<uint256>* pvNoSpendsRemaining=NULL);
+ void TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpendsRemaining=nullptr);
/** Expire all transaction (and their dependencies) in the mempool older than time. Return the number of removed transactions. */
int Expire(int64_t time);
@@ -607,7 +603,7 @@ public:
return mapTx.size();
}
- uint64_t GetTotalTxSize()
+ uint64_t GetTotalTxSize() const
{
LOCK(cs);
return totalTxSize;
@@ -623,30 +619,11 @@ public:
TxMempoolInfo info(const uint256& hash) const;
std::vector<TxMempoolInfo> infoAll() const;
- /** Estimate fee rate needed to get into the next nBlocks
- * If no answer can be given at nBlocks, return an estimate
- * at the lowest number of blocks where one can be given
- */
- CFeeRate estimateSmartFee(int nBlocks, int *answerFoundAtBlocks = NULL) const;
-
- /** Estimate fee rate needed to get into the next nBlocks */
- CFeeRate estimateFee(int nBlocks) const;
-
- /** Estimate priority needed to get into the next nBlocks
- * If no answer can be given at nBlocks, return an estimate
- * at the lowest number of blocks where one can be given
- */
- double estimateSmartPriority(int nBlocks, int *answerFoundAtBlocks = NULL) const;
-
- /** Estimate priority needed to get into the next nBlocks */
- double estimatePriority(int nBlocks) const;
-
- /** Write/Read estimates to disk */
- bool WriteFeeEstimates(CAutoFile& fileout) const;
- bool ReadFeeEstimates(CAutoFile& filein);
-
size_t DynamicMemoryUsage() const;
+ boost::signals2::signal<void (CTransactionRef)> NotifyEntryAdded;
+ boost::signals2::signal<void (CTransactionRef, MemPoolRemovalReason)> NotifyEntryRemoved;
+
private:
/** UpdateForDescendants is used by UpdateTransactionsFromBlock to update
* the descendants for a single transaction that has been added to the
@@ -683,12 +660,19 @@ private:
* transactions in a chain before we've updated all the state for the
* removal.
*/
- void removeUnchecked(txiter entry);
+ void removeUnchecked(txiter entry, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN);
};
/**
* CCoinsView that brings transactions from a memorypool into view.
* It does not check for spendings by memory pool transactions.
+ * Instead, it provides access to all Coins which are either unspent in the
+ * base CCoinsView, or are outputs from any mempool transaction!
+ * This allows transaction replacement to work as expected, as you want to
+ * have all inputs "available" to check signatures, and any cycles in the
+ * dependency graph are checked directly in AcceptToMemoryPool.
+ * It also allows you to sign a double-spend directly in signrawtransaction,
+ * as long as the conflicting transaction is not yet confirmed.
*/
class CCoinsViewMemPool : public CCoinsViewBacked
{
@@ -697,20 +681,97 @@ protected:
public:
CCoinsViewMemPool(CCoinsView* baseIn, const CTxMemPool& mempoolIn);
- bool GetCoins(const uint256 &txid, CCoins &coins) const;
- bool HaveCoins(const uint256 &txid) const;
+ bool GetCoin(const COutPoint &outpoint, Coin &coin) const override;
};
-// We want to sort transactions by coin age priority
-typedef std::pair<double, CTxMemPool::txiter> TxCoinAgePriority;
+/**
+ * DisconnectedBlockTransactions
+
+ * During the reorg, it's desirable to re-add previously confirmed transactions
+ * to the mempool, so that anything not re-confirmed in the new chain is
+ * available to be mined. However, it's more efficient to wait until the reorg
+ * is complete and process all still-unconfirmed transactions at that time,
+ * since we expect most confirmed transactions to (typically) still be
+ * confirmed in the new chain, and re-accepting to the memory pool is expensive
+ * (and therefore better to not do in the middle of reorg-processing).
+ * Instead, store the disconnected transactions (in order!) as we go, remove any
+ * that are included in blocks in the new chain, and then process the remaining
+ * still-unconfirmed transactions at the end.
+ */
-struct TxCoinAgePriorityCompare
-{
- bool operator()(const TxCoinAgePriority& a, const TxCoinAgePriority& b)
+// multi_index tag names
+struct txid_index {};
+struct insertion_order {};
+
+struct DisconnectedBlockTransactions {
+ typedef boost::multi_index_container<
+ CTransactionRef,
+ boost::multi_index::indexed_by<
+ // sorted by txid
+ boost::multi_index::hashed_unique<
+ boost::multi_index::tag<txid_index>,
+ mempoolentry_txid,
+ SaltedTxidHasher
+ >,
+ // sorted by order in the blockchain
+ boost::multi_index::sequenced<
+ boost::multi_index::tag<insertion_order>
+ >
+ >
+ > indexed_disconnected_transactions;
+
+ // It's almost certainly a logic bug if we don't clear out queuedTx before
+ // destruction, as we add to it while disconnecting blocks, and then we
+ // need to re-process remaining transactions to ensure mempool consistency.
+ // For now, assert() that we've emptied out this object on destruction.
+ // This assert() can always be removed if the reorg-processing code were
+ // to be refactored such that this assumption is no longer true (for
+ // instance if there was some other way we cleaned up the mempool after a
+ // reorg, besides draining this object).
+ ~DisconnectedBlockTransactions() { assert(queuedTx.empty()); }
+
+ indexed_disconnected_transactions queuedTx;
+ uint64_t cachedInnerUsage = 0;
+
+ // Estimate the overhead of queuedTx to be 6 pointers + an allocation, as
+ // no exact formula for boost::multi_index_contained is implemented.
+ size_t DynamicMemoryUsage() const {
+ return memusage::MallocUsage(sizeof(CTransactionRef) + 6 * sizeof(void*)) * queuedTx.size() + cachedInnerUsage;
+ }
+
+ void addTransaction(const CTransactionRef& tx)
+ {
+ queuedTx.insert(tx);
+ cachedInnerUsage += RecursiveDynamicUsage(tx);
+ }
+
+ // Remove entries based on txid_index, and update memory usage.
+ void removeForBlock(const std::vector<CTransactionRef>& vtx)
+ {
+ // Short-circuit in the common case of a block being added to the tip
+ if (queuedTx.empty()) {
+ return;
+ }
+ for (auto const &tx : vtx) {
+ auto it = queuedTx.find(tx->GetHash());
+ if (it != queuedTx.end()) {
+ cachedInnerUsage -= RecursiveDynamicUsage(*it);
+ queuedTx.erase(it);
+ }
+ }
+ }
+
+ // Remove an entry by insertion_order index, and update memory usage.
+ void removeEntry(indexed_disconnected_transactions::index<insertion_order>::type::iterator entry)
+ {
+ cachedInnerUsage -= RecursiveDynamicUsage(*entry);
+ queuedTx.get<insertion_order>().erase(entry);
+ }
+
+ void clear()
{
- if (a.first == b.first)
- return CompareTxMemPoolEntryByScore()(*(b.second), *(a.second)); //Reverse order to make sort less than
- return a.first < b.first;
+ cachedInnerUsage = 0;
+ queuedTx.clear();
}
};
diff --git a/src/ui_interface.h b/src/ui_interface.h
index 065d23fbb4..7f68c578ee 100644
--- a/src/ui_interface.h
+++ b/src/ui_interface.h
@@ -12,9 +12,7 @@
#include <boost/signals2/last_value.hpp>
#include <boost/signals2/signal.hpp>
-class CBasicKeyStore;
class CWallet;
-class uint256;
class CBlockIndex;
/** General change type (added, updated, removed). */
@@ -96,8 +94,11 @@ public:
/** A wallet has been loaded. */
boost::signals2::signal<void (CWallet* wallet)> LoadWallet;
- /** Show progress e.g. for verifychain */
- boost::signals2::signal<void (const std::string &title, int nProgress)> ShowProgress;
+ /**
+ * Show progress e.g. for verifychain.
+ * resume_possible indicates shutting down now will result in the current progress action resuming upon restart.
+ */
+ boost::signals2::signal<void (const std::string &title, int nProgress, bool resume_possible)> ShowProgress;
/** New block has been accepted */
boost::signals2::signal<void (bool, const CBlockIndex *)> NotifyBlockTip;
diff --git a/src/uint256.cpp b/src/uint256.cpp
index bd3d017085..736a0d4fe2 100644
--- a/src/uint256.cpp
+++ b/src/uint256.cpp
@@ -14,16 +14,13 @@ template <unsigned int BITS>
base_blob<BITS>::base_blob(const std::vector<unsigned char>& vch)
{
assert(vch.size() == sizeof(data));
- memcpy(data, &vch[0], sizeof(data));
+ memcpy(data, vch.data(), sizeof(data));
}
template <unsigned int BITS>
std::string base_blob<BITS>::GetHex() const
{
- char psz[sizeof(data) * 2 + 1];
- for (unsigned int i = 0; i < sizeof(data); i++)
- sprintf(psz + i * 2, "%02x", data[sizeof(data) - i - 1]);
- return std::string(psz, psz + sizeof(data) * 2);
+ return HexStr(std::reverse_iterator<const uint8_t*>(data + sizeof(data)), std::reverse_iterator<const uint8_t*>(data));
}
template <unsigned int BITS>
diff --git a/src/uint256.h b/src/uint256.h
index a92ce07f11..94a4f7fc30 100644
--- a/src/uint256.h
+++ b/src/uint256.h
@@ -111,7 +111,6 @@ public:
class uint160 : public base_blob<160> {
public:
uint160() {}
- uint160(const base_blob<160>& b) : base_blob<160>(b) {}
explicit uint160(const std::vector<unsigned char>& vch) : base_blob<160>(vch) {}
};
@@ -123,7 +122,6 @@ public:
class uint256 : public base_blob<256> {
public:
uint256() {}
- uint256(const base_blob<256>& b) : base_blob<256>(b) {}
explicit uint256(const std::vector<unsigned char>& vch) : base_blob<256>(vch) {}
/** A cheap hash function that just returns 64 bits from the result, it can be
diff --git a/src/undo.h b/src/undo.h
index a94e31f5cc..a720de4ac5 100644
--- a/src/undo.h
+++ b/src/undo.h
@@ -7,58 +7,91 @@
#define BITCOIN_UNDO_H
#include "compressor.h"
+#include "consensus/consensus.h"
#include "primitives/transaction.h"
#include "serialize.h"
/** Undo information for a CTxIn
*
- * Contains the prevout's CTxOut being spent, and if this was the
- * last output of the affected transaction, its metadata as well
- * (coinbase or not, height, transaction version)
+ * Contains the prevout's CTxOut being spent, and its metadata as well
+ * (coinbase or not, height). The serialization contains a dummy value of
+ * zero. This is be compatible with older versions which expect to see
+ * the transaction version there.
*/
-class CTxInUndo
+class TxInUndoSerializer
{
-public:
- CTxOut txout; // the txout data before being spent
- bool fCoinBase; // if the outpoint was the last unspent: whether it belonged to a coinbase
- unsigned int nHeight; // if the outpoint was the last unspent: its height
- int nVersion; // if the outpoint was the last unspent: its version
-
- CTxInUndo() : txout(), fCoinBase(false), nHeight(0), nVersion(0) {}
- CTxInUndo(const CTxOut &txoutIn, bool fCoinBaseIn = false, unsigned int nHeightIn = 0, int nVersionIn = 0) : txout(txoutIn), fCoinBase(fCoinBaseIn), nHeight(nHeightIn), nVersion(nVersionIn) { }
+ const Coin* txout;
+public:
template<typename Stream>
void Serialize(Stream &s) const {
- ::Serialize(s, VARINT(nHeight*2+(fCoinBase ? 1 : 0)));
- if (nHeight > 0)
- ::Serialize(s, VARINT(this->nVersion));
- ::Serialize(s, CTxOutCompressor(REF(txout)));
+ ::Serialize(s, VARINT(txout->nHeight * 2 + (txout->fCoinBase ? 1 : 0)));
+ if (txout->nHeight > 0) {
+ // Required to maintain compatibility with older undo format.
+ ::Serialize(s, (unsigned char)0);
+ }
+ ::Serialize(s, CTxOutCompressor(REF(txout->out)));
}
+ explicit TxInUndoSerializer(const Coin* coin) : txout(coin) {}
+};
+
+class TxInUndoDeserializer
+{
+ Coin* txout;
+
+public:
template<typename Stream>
void Unserialize(Stream &s) {
unsigned int nCode = 0;
::Unserialize(s, VARINT(nCode));
- nHeight = nCode / 2;
- fCoinBase = nCode & 1;
- if (nHeight > 0)
- ::Unserialize(s, VARINT(this->nVersion));
- ::Unserialize(s, REF(CTxOutCompressor(REF(txout))));
+ txout->nHeight = nCode / 2;
+ txout->fCoinBase = nCode & 1;
+ if (txout->nHeight > 0) {
+ // Old versions stored the version number for the last spend of
+ // a transaction's outputs. Non-final spends were indicated with
+ // height = 0.
+ int nVersionDummy;
+ ::Unserialize(s, VARINT(nVersionDummy));
+ }
+ ::Unserialize(s, REF(CTxOutCompressor(REF(txout->out))));
}
+
+ explicit TxInUndoDeserializer(Coin* coin) : txout(coin) {}
};
+static const size_t MIN_TRANSACTION_INPUT_WEIGHT = WITNESS_SCALE_FACTOR * ::GetSerializeSize(CTxIn(), SER_NETWORK, PROTOCOL_VERSION);
+static const size_t MAX_INPUTS_PER_BLOCK = MAX_BLOCK_WEIGHT / MIN_TRANSACTION_INPUT_WEIGHT;
+
/** Undo information for a CTransaction */
class CTxUndo
{
public:
// undo information for all txins
- std::vector<CTxInUndo> vprevout;
+ std::vector<Coin> vprevout;
- ADD_SERIALIZE_METHODS;
+ template <typename Stream>
+ void Serialize(Stream& s) const {
+ // TODO: avoid reimplementing vector serializer
+ uint64_t count = vprevout.size();
+ ::Serialize(s, COMPACTSIZE(REF(count)));
+ for (const auto& prevout : vprevout) {
+ ::Serialize(s, REF(TxInUndoSerializer(&prevout)));
+ }
+ }
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action) {
- READWRITE(vprevout);
+ template <typename Stream>
+ void Unserialize(Stream& s) {
+ // TODO: avoid reimplementing vector deserializer
+ uint64_t count = 0;
+ ::Unserialize(s, COMPACTSIZE(count));
+ if (count > MAX_INPUTS_PER_BLOCK) {
+ throw std::ios_base::failure("Too many input undo records");
+ }
+ vprevout.resize(count);
+ for (auto& prevout : vprevout) {
+ ::Unserialize(s, REF(TxInUndoDeserializer(&prevout)));
+ }
}
};
diff --git a/src/univalue/lib/univalue_utffilter.h b/src/univalue/lib/univalue_utffilter.h
index 0e330dce9c..2fb6a492d1 100644
--- a/src/univalue/lib/univalue_utffilter.h
+++ b/src/univalue/lib/univalue_utffilter.h
@@ -13,7 +13,7 @@
class JSONUTF8StringFilter
{
public:
- JSONUTF8StringFilter(std::string &s):
+ explicit JSONUTF8StringFilter(std::string &s):
str(s), is_valid(true), codepoint(0), state(0), surpair(0)
{
}
diff --git a/src/util.cpp b/src/util.cpp
index 08ee6b8b87..51ccc94787 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -10,9 +10,9 @@
#include "util.h"
#include "chainparamsbase.h"
+#include "fs.h"
#include "random.h"
#include "serialize.h"
-#include "sync.h"
#include "utilstrencodings.h"
#include "utiltime.h"
@@ -72,41 +72,25 @@
#include <sys/prctl.h>
#endif
+#ifdef HAVE_MALLOPT_ARENA_MAX
+#include <malloc.h>
+#endif
+
#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
-#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/predicate.hpp> // for startswith() and endswith()
-#include <boost/filesystem.hpp>
-#include <boost/filesystem/fstream.hpp>
-#include <boost/foreach.hpp>
#include <boost/program_options/detail/config_file.hpp>
-#include <boost/program_options/parsers.hpp>
#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
-// See also: http://stackoverflow.com/questions/10020179/compilation-fail-in-boost-librairies-program-options
-// http://clang.debian.net/status.php?version=3.0&key=CANNOT_FIND_FUNCTION
-namespace boost {
-
- namespace program_options {
- std::string to_internal(const std::string&);
- }
-
-} // namespace boost
-
-using namespace std;
+// Application startup time (used for uptime calculation)
+const int64_t nStartupTime = GetTime();
const char * const BITCOIN_CONF_FILENAME = "bitcoin.conf";
const char * const BITCOIN_PID_FILENAME = "bitcoind.pid";
-CCriticalSection cs_args;
-map<string, string> mapArgs;
-static map<string, vector<string> > _mapMultiArgs;
-const map<string, vector<string> >& mapMultiArgs = _mapMultiArgs;
-bool fDebug = false;
+ArgsManager gArgs;
bool fPrintToConsole = false;
bool fPrintToDebugLog = true;
@@ -116,27 +100,28 @@ bool fLogIPs = DEFAULT_LOGIPS;
std::atomic<bool> fReopenDebugLog(false);
CTranslationInterface translationInterface;
+/** Log categories bitfield. */
+std::atomic<uint32_t> logCategories(0);
+
/** Init OpenSSL library multithreading support */
-static CCriticalSection** ppmutexOpenSSL;
+static std::unique_ptr<CCriticalSection[]> ppmutexOpenSSL;
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]);
+ ENTER_CRITICAL_SECTION(ppmutexOpenSSL[i]);
} else {
- LEAVE_CRITICAL_SECTION(*ppmutexOpenSSL[i]);
+ LEAVE_CRITICAL_SECTION(ppmutexOpenSSL[i]);
}
}
-// Init
+// Singleton for wrapping OpenSSL setup/teardown.
class CInit
{
public:
CInit()
{
// Init OpenSSL library multithreading support
- ppmutexOpenSSL = (CCriticalSection**)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(CCriticalSection*));
- for (int i = 0; i < CRYPTO_num_locks(); i++)
- ppmutexOpenSSL[i] = new CCriticalSection();
+ ppmutexOpenSSL.reset(new CCriticalSection[CRYPTO_num_locks()]);
CRYPTO_set_locking_callback(locking_callback);
// OpenSSL can optionally load a config file which lists optional loadable modules and engines.
@@ -159,10 +144,9 @@ public:
// Securely erase the memory used by the PRNG
RAND_cleanup();
// Shutdown OpenSSL library multithreading support
- CRYPTO_set_locking_callback(NULL);
- for (int i = 0; i < CRYPTO_num_locks(); i++)
- delete ppmutexOpenSSL[i];
- OPENSSL_free(ppmutexOpenSSL);
+ CRYPTO_set_locking_callback(nullptr);
+ // Clear the set of locks now to maintain symmetry with the constructor.
+ ppmutexOpenSSL.reset();
}
}
instance_of_cinit;
@@ -189,9 +173,9 @@ static boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT;
* 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 FILE* fileout = nullptr;
+static boost::mutex* mutexDebugLog = nullptr;
+static std::list<std::string>* vMsgsBeforeOpenLog;
static int FileWriteStr(const std::string &str, FILE *fp)
{
@@ -200,9 +184,9 @@ static int FileWriteStr(const std::string &str, FILE *fp)
static void DebugPrintInit()
{
- assert(mutexDebugLog == NULL);
+ assert(mutexDebugLog == nullptr);
mutexDebugLog = new boost::mutex();
- vMsgsBeforeOpenLog = new list<string>;
+ vMsgsBeforeOpenLog = new std::list<std::string>;
}
void OpenDebugLog()
@@ -210,52 +194,102 @@ void OpenDebugLog()
boost::call_once(&DebugPrintInit, debugPrintInitFlag);
boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);
- assert(fileout == NULL);
+ assert(fileout == nullptr);
assert(vMsgsBeforeOpenLog);
- boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
- fileout = fopen(pathDebug.string().c_str(), "a");
- if (fileout) setbuf(fileout, NULL); // unbuffered
-
- // dump buffered messages from before we opened the log
- while (!vMsgsBeforeOpenLog->empty()) {
- FileWriteStr(vMsgsBeforeOpenLog->front(), fileout);
- vMsgsBeforeOpenLog->pop_front();
+ fs::path pathDebug = GetDataDir() / "debug.log";
+ fileout = fsbridge::fopen(pathDebug, "a");
+ if (fileout) {
+ setbuf(fileout, nullptr); // unbuffered
+ // dump buffered messages from before we opened the log
+ while (!vMsgsBeforeOpenLog->empty()) {
+ FileWriteStr(vMsgsBeforeOpenLog->front(), fileout);
+ vMsgsBeforeOpenLog->pop_front();
+ }
}
delete vMsgsBeforeOpenLog;
- vMsgsBeforeOpenLog = NULL;
+ vMsgsBeforeOpenLog = nullptr;
+}
+
+struct CLogCategoryDesc
+{
+ uint32_t flag;
+ std::string category;
+};
+
+const CLogCategoryDesc LogCategories[] =
+{
+ {BCLog::NONE, "0"},
+ {BCLog::NET, "net"},
+ {BCLog::TOR, "tor"},
+ {BCLog::MEMPOOL, "mempool"},
+ {BCLog::HTTP, "http"},
+ {BCLog::BENCH, "bench"},
+ {BCLog::ZMQ, "zmq"},
+ {BCLog::DB, "db"},
+ {BCLog::RPC, "rpc"},
+ {BCLog::ESTIMATEFEE, "estimatefee"},
+ {BCLog::ADDRMAN, "addrman"},
+ {BCLog::SELECTCOINS, "selectcoins"},
+ {BCLog::REINDEX, "reindex"},
+ {BCLog::CMPCTBLOCK, "cmpctblock"},
+ {BCLog::RAND, "rand"},
+ {BCLog::PRUNE, "prune"},
+ {BCLog::PROXY, "proxy"},
+ {BCLog::MEMPOOLREJ, "mempoolrej"},
+ {BCLog::LIBEVENT, "libevent"},
+ {BCLog::COINDB, "coindb"},
+ {BCLog::QT, "qt"},
+ {BCLog::LEVELDB, "leveldb"},
+ {BCLog::ALL, "1"},
+ {BCLog::ALL, "all"},
+};
+
+bool GetLogCategory(uint32_t *f, const std::string *str)
+{
+ if (f && str) {
+ if (*str == "") {
+ *f = BCLog::ALL;
+ return true;
+ }
+ for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {
+ if (LogCategories[i].category == *str) {
+ *f = LogCategories[i].flag;
+ return true;
+ }
+ }
+ }
+ return false;
}
-bool LogAcceptCategory(const char* category)
+std::string ListLogCategories()
{
- if (category != NULL)
- {
- if (!fDebug)
- return false;
-
- // Give each thread quick access to -debug settings.
- // This helps prevent issues debugging global destructors,
- // where mapMultiArgs might be deleted before another
- // global destructor calls LogPrint()
- static boost::thread_specific_ptr<set<string> > ptrCategory;
- if (ptrCategory.get() == NULL)
- {
- if (mapMultiArgs.count("-debug")) {
- const vector<string>& categories = mapMultiArgs.at("-debug");
- ptrCategory.reset(new set<string>(categories.begin(), categories.end()));
- // thread_specific_ptr automatically deletes the set when the thread ends.
- } else
- ptrCategory.reset(new set<string>());
+ std::string ret;
+ int outcount = 0;
+ for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {
+ // Omit the special cases.
+ if (LogCategories[i].flag != BCLog::NONE && LogCategories[i].flag != BCLog::ALL) {
+ if (outcount != 0) ret += ", ";
+ ret += LogCategories[i].category;
+ outcount++;
}
- const set<string>& setCategories = *ptrCategory.get();
+ }
+ return ret;
+}
- // 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;
+std::vector<CLogCategoryActive> ListActiveLogCategories()
+{
+ std::vector<CLogCategoryActive> ret;
+ for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {
+ // Omit the special cases.
+ if (LogCategories[i].flag != BCLog::NONE && LogCategories[i].flag != BCLog::ALL) {
+ CLogCategoryActive catActive;
+ catActive.category = LogCategories[i].category;
+ catActive.active = LogAcceptCategory(LogCategories[i].flag);
+ ret.push_back(catActive);
+ }
}
- return true;
+ return ret;
}
/**
@@ -265,16 +299,20 @@ bool LogAcceptCategory(const char* category)
*/
static std::string LogTimestampStr(const std::string &str, std::atomic_bool *fStartedNewLine)
{
- string strStamped;
+ std::string strStamped;
if (!fLogTimestamps)
return str;
if (*fStartedNewLine) {
- int64_t nTimeMicros = GetLogTimeMicros();
+ int64_t nTimeMicros = GetTimeMicros();
strStamped = DateTimeStrFormat("%Y-%m-%d %H:%M:%S", nTimeMicros/1000000);
if (fLogTimeMicros)
strStamped += strprintf(".%06d", nTimeMicros%1000000);
+ int64_t mocktime = GetMockTime();
+ if (mocktime) {
+ strStamped += " (mocktime: " + DateTimeStrFormat("%Y-%m-%d %H:%M:%S", mocktime) + ")";
+ }
strStamped += ' ' + str;
} else
strStamped = str;
@@ -292,7 +330,7 @@ int LogPrintStr(const std::string &str)
int ret = 0; // Returns total number of characters written
static std::atomic_bool fStartedNewLine(true);
- string strTimestamped = LogTimestampStr(str, &fStartedNewLine);
+ std::string strTimestamped = LogTimestampStr(str, &fStartedNewLine);
if (fPrintToConsole)
{
@@ -306,7 +344,7 @@ int LogPrintStr(const std::string &str)
boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);
// buffer if we haven't opened the log yet
- if (fileout == NULL) {
+ if (fileout == nullptr) {
assert(vMsgsBeforeOpenLog);
ret = strTimestamped.length();
vMsgsBeforeOpenLog->push_back(strTimestamped);
@@ -316,9 +354,9 @@ int LogPrintStr(const std::string &str)
// 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
+ fs::path pathDebug = GetDataDir() / "debug.log";
+ if (fsbridge::freopen(pathDebug,"a",fileout) != nullptr)
+ setbuf(fileout, nullptr); // unbuffered
}
ret = FileWriteStr(strTimestamped, fileout);
@@ -345,11 +383,11 @@ static void InterpretNegativeSetting(std::string& strKey, std::string& strValue)
}
}
-void ParseParameters(int argc, const char* const argv[])
+void ArgsManager::ParseParameters(int argc, const char* const argv[])
{
LOCK(cs_args);
mapArgs.clear();
- _mapMultiArgs.clear();
+ mapMultiArgs.clear();
for (int i = 1; i < argc; i++)
{
@@ -377,50 +415,57 @@ void ParseParameters(int argc, const char* const argv[])
InterpretNegativeSetting(str, strValue);
mapArgs[str] = strValue;
- _mapMultiArgs[str].push_back(strValue);
+ mapMultiArgs[str].push_back(strValue);
}
}
-bool IsArgSet(const std::string& strArg)
+std::vector<std::string> ArgsManager::GetArgs(const std::string& strArg) const
+{
+ LOCK(cs_args);
+ auto it = mapMultiArgs.find(strArg);
+ if (it != mapMultiArgs.end()) return it->second;
+ return {};
+}
+
+bool ArgsManager::IsArgSet(const std::string& strArg) const
{
LOCK(cs_args);
return mapArgs.count(strArg);
}
-std::string GetArg(const std::string& strArg, const std::string& strDefault)
+std::string ArgsManager::GetArg(const std::string& strArg, const std::string& strDefault) const
{
LOCK(cs_args);
- if (mapArgs.count(strArg))
- return mapArgs[strArg];
+ auto it = mapArgs.find(strArg);
+ if (it != mapArgs.end()) return it->second;
return strDefault;
}
-int64_t GetArg(const std::string& strArg, int64_t nDefault)
+int64_t ArgsManager::GetArg(const std::string& strArg, int64_t nDefault) const
{
LOCK(cs_args);
- if (mapArgs.count(strArg))
- return atoi64(mapArgs[strArg]);
+ auto it = mapArgs.find(strArg);
+ if (it != mapArgs.end()) return atoi64(it->second);
return nDefault;
}
-bool GetBoolArg(const std::string& strArg, bool fDefault)
+bool ArgsManager::GetBoolArg(const std::string& strArg, bool fDefault) const
{
LOCK(cs_args);
- if (mapArgs.count(strArg))
- return InterpretBool(mapArgs[strArg]);
+ auto it = mapArgs.find(strArg);
+ if (it != mapArgs.end()) return InterpretBool(it->second);
return fDefault;
}
-bool SoftSetArg(const std::string& strArg, const std::string& strValue)
+bool ArgsManager::SoftSetArg(const std::string& strArg, const std::string& strValue)
{
LOCK(cs_args);
- if (mapArgs.count(strArg))
- return false;
- mapArgs[strArg] = strValue;
+ if (IsArgSet(strArg)) return false;
+ ForceSetArg(strArg, strValue);
return true;
}
-bool SoftSetBoolArg(const std::string& strArg, bool fValue)
+bool ArgsManager::SoftSetBoolArg(const std::string& strArg, bool fValue)
{
if (fValue)
return SoftSetArg(strArg, std::string("1"));
@@ -428,10 +473,11 @@ bool SoftSetBoolArg(const std::string& strArg, bool fValue)
return SoftSetArg(strArg, std::string("0"));
}
-void ForceSetArg(const std::string& strArg, const std::string& strValue)
+void ArgsManager::ForceSetArg(const std::string& strArg, const std::string& strValue)
{
LOCK(cs_args);
mapArgs[strArg] = strValue;
+ mapMultiArgs[strArg] = {strValue};
}
@@ -455,7 +501,7 @@ static std::string FormatException(const std::exception* pex, const char* pszThr
{
#ifdef WIN32
char pszModule[MAX_PATH] = "";
- GetModuleFileNameA(NULL, pszModule, sizeof(pszModule));
+ GetModuleFileNameA(nullptr, pszModule, sizeof(pszModule));
#else
const char* pszModule = "bitcoin";
#endif
@@ -474,9 +520,8 @@ void PrintExceptionContinue(const std::exception* pex, const char* pszThread)
fprintf(stderr, "\n\n************************\n%s\n", message.c_str());
}
-boost::filesystem::path GetDefaultDataDir()
+fs::path GetDefaultDataDir()
{
- namespace fs = boost::filesystem;
// Windows < Vista: C:\Documents and Settings\Username\Application Data\Bitcoin
// Windows >= Vista: C:\Users\Username\AppData\Roaming\Bitcoin
// Mac: ~/Library/Application Support/Bitcoin
@@ -487,7 +532,7 @@ boost::filesystem::path GetDefaultDataDir()
#else
fs::path pathRet;
char* pszHome = getenv("HOME");
- if (pszHome == NULL || strlen(pszHome) == 0)
+ if (pszHome == nullptr || strlen(pszHome) == 0)
pathRet = fs::path("/");
else
pathRet = fs::path(pszHome);
@@ -501,13 +546,12 @@ boost::filesystem::path GetDefaultDataDir()
#endif
}
-static boost::filesystem::path pathCached;
-static boost::filesystem::path pathCachedNetSpecific;
+static fs::path pathCached;
+static fs::path pathCachedNetSpecific;
static CCriticalSection csPathCached;
-const boost::filesystem::path &GetDataDir(bool fNetSpecific)
+const fs::path &GetDataDir(bool fNetSpecific)
{
- namespace fs = boost::filesystem;
LOCK(csPathCached);
@@ -518,8 +562,8 @@ const boost::filesystem::path &GetDataDir(bool fNetSpecific)
if (!path.empty())
return path;
- if (IsArgSet("-datadir")) {
- path = fs::system_complete(GetArg("-datadir", ""));
+ if (gArgs.IsArgSet("-datadir")) {
+ path = fs::system_complete(gArgs.GetArg("-datadir", ""));
if (!fs::is_directory(path)) {
path = "";
return path;
@@ -539,39 +583,39 @@ void ClearDatadirCache()
{
LOCK(csPathCached);
- pathCached = boost::filesystem::path();
- pathCachedNetSpecific = boost::filesystem::path();
+ pathCached = fs::path();
+ pathCachedNetSpecific = fs::path();
}
-boost::filesystem::path GetConfigFile(const std::string& confPath)
+fs::path GetConfigFile(const std::string& confPath)
{
- boost::filesystem::path pathConfigFile(confPath);
+ fs::path pathConfigFile(confPath);
if (!pathConfigFile.is_complete())
pathConfigFile = GetDataDir(false) / pathConfigFile;
return pathConfigFile;
}
-void ReadConfigFile(const std::string& confPath)
+void ArgsManager::ReadConfigFile(const std::string& confPath)
{
- boost::filesystem::ifstream streamConfig(GetConfigFile(confPath));
+ fs::ifstream streamConfig(GetConfigFile(confPath));
if (!streamConfig.good())
return; // No bitcoin.conf file is OK
{
LOCK(cs_args);
- set<string> setOptions;
+ std::set<std::string> setOptions;
setOptions.insert("*");
for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it)
{
// Don't overwrite existing settings so command line settings override bitcoin.conf
- string strKey = string("-") + it->string_key;
- string strValue = it->value[0];
+ std::string strKey = std::string("-") + it->string_key;
+ std::string strValue = it->value[0];
InterpretNegativeSetting(strKey, strValue);
if (mapArgs.count(strKey) == 0)
mapArgs[strKey] = strValue;
- _mapMultiArgs[strKey].push_back(strValue);
+ mapMultiArgs[strKey].push_back(strValue);
}
}
// If datadir is changed in .conf file:
@@ -579,16 +623,16 @@ void ReadConfigFile(const std::string& confPath)
}
#ifndef WIN32
-boost::filesystem::path GetPidFile()
+fs::path GetPidFile()
{
- boost::filesystem::path pathPidFile(GetArg("-pid", BITCOIN_PID_FILENAME));
+ fs::path pathPidFile(gArgs.GetArg("-pid", BITCOIN_PID_FILENAME));
if (!pathPidFile.is_complete()) pathPidFile = GetDataDir() / pathPidFile;
return pathPidFile;
}
-void CreatePidFile(const boost::filesystem::path &path, pid_t pid)
+void CreatePidFile(const fs::path &path, pid_t pid)
{
- FILE* file = fopen(path.string().c_str(), "w");
+ FILE* file = fsbridge::fopen(path, "w");
if (file)
{
fprintf(file, "%d\n", pid);
@@ -597,7 +641,7 @@ void CreatePidFile(const boost::filesystem::path &path, pid_t pid)
}
#endif
-bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest)
+bool RenameOver(fs::path src, fs::path dest)
{
#ifdef WIN32
return MoveFileExA(src.string().c_str(), dest.string().c_str(),
@@ -609,21 +653,21 @@ bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest)
}
/**
- * Ignores exceptions thrown by Boost's create_directory if the requested directory exists.
+ * Ignores exceptions thrown by Boost's create_directories if the requested directory exists.
* Specifically handles case where path p exists, but it wasn't possible for the user to
* write to the parent directory.
*/
-bool TryCreateDirectory(const boost::filesystem::path& p)
+bool TryCreateDirectories(const fs::path& p)
{
try
{
- return boost::filesystem::create_directory(p);
- } catch (const boost::filesystem::filesystem_error&) {
- if (!boost::filesystem::exists(p) || !boost::filesystem::is_directory(p))
+ return fs::create_directories(p);
+ } catch (const fs::filesystem_error&) {
+ if (!fs::exists(p) || !fs::is_directory(p))
throw;
}
- // create_directory didn't create the directory, it had to have existed already
+ // create_directories didn't create the directory, it had to have existed already
return false;
}
@@ -723,36 +767,38 @@ void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {
void ShrinkDebugFile()
{
+ // Amount of debug.log to save at end when shrinking (must fit in memory)
+ constexpr size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000;
// Scroll debug.log if it's getting too big
- boost::filesystem::path pathLog = GetDataDir() / "debug.log";
- FILE* file = fopen(pathLog.string().c_str(), "r");
- if (file && boost::filesystem::file_size(pathLog) > 10 * 1000000)
+ fs::path pathLog = GetDataDir() / "debug.log";
+ FILE* file = fsbridge::fopen(pathLog, "r");
+ // If debug.log file is more than 10% bigger the RECENT_DEBUG_HISTORY_SIZE
+ // trim it down by saving only the last RECENT_DEBUG_HISTORY_SIZE bytes
+ if (file && fs::file_size(pathLog) > 11 * (RECENT_DEBUG_HISTORY_SIZE / 10))
{
// Restart the file with some of the end
- std::vector <char> vch(200000,0);
+ std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0);
fseek(file, -((long)vch.size()), SEEK_END);
int nBytes = fread(vch.data(), 1, vch.size(), file);
fclose(file);
- file = fopen(pathLog.string().c_str(), "w");
+ file = fsbridge::fopen(pathLog, "w");
if (file)
{
fwrite(vch.data(), 1, nBytes, file);
fclose(file);
}
}
- else if (file != NULL)
+ else if (file != nullptr)
fclose(file);
}
#ifdef WIN32
-boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate)
+fs::path GetSpecialFolderPath(int nFolder, bool fCreate)
{
- namespace fs = boost::filesystem;
-
char pszPath[MAX_PATH] = "";
- if(SHGetSpecialFolderPathA(NULL, pszPath, nFolder, fCreate))
+ if(SHGetSpecialFolderPathA(nullptr, pszPath, nFolder, fCreate))
{
return fs::path(pszPath);
}
@@ -764,6 +810,7 @@ boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate)
void runCommand(const std::string& strCommand)
{
+ if (strCommand.empty()) return;
int nErr = ::system(strCommand.c_str());
if (nErr)
LogPrintf("runCommand error: system(%s) returned %d\n", strCommand, nErr);
@@ -787,6 +834,16 @@ void RenameThread(const char* name)
void SetupEnvironment()
{
+#ifdef HAVE_MALLOPT_ARENA_MAX
+ // glibc-specific: On 32-bit systems set the number of arenas to 1.
+ // By default, since glibc 2.10, the C library will create up to two heap
+ // arenas per core. This is known to cause excessive virtual address space
+ // usage in our usage. Work around it by setting the maximum number of
+ // arenas to 1.
+ if (sizeof(void*) == 4) {
+ mallopt(M_ARENA_MAX, 1);
+ }
+#endif
// On most POSIX systems (e.g. Linux, but not BSD) the environment's locale
// may be invalid, in which case the "C" locale is used as fallback.
#if !defined(WIN32) && !defined(MAC_OSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
@@ -799,9 +856,9 @@ void SetupEnvironment()
// The path locale is lazy initialized and to avoid deinitialization errors
// in multithreading environments, it is set explicitly by the main thread.
// A dummy locale is used to extract the internal default locale, used by
- // boost::filesystem::path, which is then used to explicitly imbue the path.
- std::locale loc = boost::filesystem::path::imbue(std::locale::classic());
- boost::filesystem::path::imbue(loc);
+ // fs::path, which is then used to explicitly imbue the path.
+ std::locale loc = fs::path::imbue(std::locale::classic());
+ fs::path::imbue(loc);
}
bool SetupNetworking()
@@ -835,3 +892,9 @@ std::string CopyrightHolders(const std::string& strPrefix)
}
return strCopyrightHolders;
}
+
+// Obtain the application startup time (used for uptime calculation)
+int64_t GetStartupTime()
+{
+ return nStartupTime;
+}
diff --git a/src/util.h b/src/util.h
index e27ce121c8..480a80c0a3 100644
--- a/src/util.h
+++ b/src/util.h
@@ -5,7 +5,7 @@
/**
* Server/client environment: argument handling, config file parsing,
- * logging, thread wrappers
+ * logging, thread wrappers, startup time
*/
#ifndef BITCOIN_UTIL_H
#define BITCOIN_UTIL_H
@@ -15,6 +15,8 @@
#endif
#include "compat.h"
+#include "fs.h"
+#include "sync.h"
#include "tinyformat.h"
#include "utiltime.h"
@@ -25,9 +27,10 @@
#include <string>
#include <vector>
-#include <boost/filesystem/path.hpp>
#include <boost/signals2/signal.hpp>
-#include <boost/thread/exceptions.hpp>
+
+// Application startup time (used for uptime calculation)
+int64_t GetStartupTime();
static const bool DEFAULT_LOGTIMEMICROS = false;
static const bool DEFAULT_LOGIPS = false;
@@ -41,8 +44,6 @@ public:
boost::signals2::signal<std::string (const char* psz)> Translate;
};
-extern const std::map<std::string, std::vector<std::string> >& mapMultiArgs;
-extern bool fDebug;
extern bool fPrintToConsole;
extern bool fPrintToDebugLog;
@@ -55,6 +56,8 @@ extern CTranslationInterface translationInterface;
extern const char * const BITCOIN_CONF_FILENAME;
extern const char * const BITCOIN_PID_FILENAME;
+extern std::atomic<uint32_t> logCategories;
+
/**
* Translation function: Call Translate signal on UI interface, which returns a boost::optional result.
* If no translation slot is registered, nothing is returned, and simply return the input.
@@ -68,20 +71,88 @@ inline std::string _(const char* psz)
void SetupEnvironment();
bool SetupNetworking();
+struct CLogCategoryActive
+{
+ std::string category;
+ bool active;
+};
+
+namespace BCLog {
+ enum LogFlags : uint32_t {
+ NONE = 0,
+ NET = (1 << 0),
+ TOR = (1 << 1),
+ MEMPOOL = (1 << 2),
+ HTTP = (1 << 3),
+ BENCH = (1 << 4),
+ ZMQ = (1 << 5),
+ DB = (1 << 6),
+ RPC = (1 << 7),
+ ESTIMATEFEE = (1 << 8),
+ ADDRMAN = (1 << 9),
+ SELECTCOINS = (1 << 10),
+ REINDEX = (1 << 11),
+ CMPCTBLOCK = (1 << 12),
+ RAND = (1 << 13),
+ PRUNE = (1 << 14),
+ PROXY = (1 << 15),
+ MEMPOOLREJ = (1 << 16),
+ LIBEVENT = (1 << 17),
+ COINDB = (1 << 18),
+ QT = (1 << 19),
+ LEVELDB = (1 << 20),
+ ALL = ~(uint32_t)0,
+ };
+}
/** Return true if log accepts specified category */
-bool LogAcceptCategory(const char* category);
+static inline bool LogAcceptCategory(uint32_t category)
+{
+ return (logCategories.load(std::memory_order_relaxed) & category) != 0;
+}
+
+/** Returns a string with the log categories. */
+std::string ListLogCategories();
+
+/** Returns a vector of the active log categories. */
+std::vector<CLogCategoryActive> ListActiveLogCategories();
+
+/** Return true if str parses as a log category and set the flags in f */
+bool GetLogCategory(uint32_t *f, const std::string *str);
+
/** Send a string to the log output */
int LogPrintStr(const std::string &str);
-#define LogPrint(category, ...) do { \
- if (LogAcceptCategory((category))) { \
- LogPrintStr(tfm::format(__VA_ARGS__)); \
+/** Get format string from VA_ARGS for error reporting */
+template<typename... Args> std::string FormatStringFromLogArgs(const char *fmt, const Args&... args) { return fmt; }
+
+static inline void MarkUsed() {}
+template<typename T, typename... Args> static inline void MarkUsed(const T& t, const Args&... args)
+{
+ (void)t;
+ MarkUsed(args...);
+}
+
+#ifdef USE_COVERAGE
+#define LogPrintf(...) do { MarkUsed(__VA_ARGS__); } while(0)
+#define LogPrint(category, ...) do { MarkUsed(__VA_ARGS__); } while(0)
+#else
+#define LogPrintf(...) do { \
+ std::string _log_msg_; /* Unlikely name to avoid shadowing variables */ \
+ try { \
+ _log_msg_ = tfm::format(__VA_ARGS__); \
+ } catch (tinyformat::format_error &fmterr) { \
+ /* Original format string will have newline so don't add one here */ \
+ _log_msg_ = "Error \"" + std::string(fmterr.what()) + "\" while formatting log message: " + FormatStringFromLogArgs(__VA_ARGS__); \
} \
+ LogPrintStr(_log_msg_); \
} while(0)
-#define LogPrintf(...) do { \
- LogPrintStr(tfm::format(__VA_ARGS__)); \
+#define LogPrint(category, ...) do { \
+ if (LogAcceptCategory((category))) { \
+ LogPrintf(__VA_ARGS__); \
+ } \
} while(0)
+#endif
template<typename... Args>
bool error(const char* fmt, const Args&... args)
@@ -91,24 +162,22 @@ bool error(const char* fmt, const Args&... args)
}
void PrintExceptionContinue(const std::exception *pex, const char* pszThread);
-void ParseParameters(int argc, const char*const argv[]);
void FileCommit(FILE *file);
bool TruncateFile(FILE *file, unsigned int length);
int RaiseFileDescriptorLimit(int nMinFD);
void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length);
-bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest);
-bool TryCreateDirectory(const boost::filesystem::path& p);
-boost::filesystem::path GetDefaultDataDir();
-const boost::filesystem::path &GetDataDir(bool fNetSpecific = true);
+bool RenameOver(fs::path src, fs::path dest);
+bool TryCreateDirectories(const fs::path& p);
+fs::path GetDefaultDataDir();
+const fs::path &GetDataDir(bool fNetSpecific = true);
void ClearDatadirCache();
-boost::filesystem::path GetConfigFile(const std::string& confPath);
+fs::path GetConfigFile(const std::string& confPath);
#ifndef WIN32
-boost::filesystem::path GetPidFile();
-void CreatePidFile(const boost::filesystem::path &path, pid_t pid);
+fs::path GetPidFile();
+void CreatePidFile(const fs::path &path, pid_t pid);
#endif
-void ReadConfigFile(const std::string& confPath);
#ifdef WIN32
-boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
+fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
#endif
void OpenDebugLog();
void ShrinkDebugFile();
@@ -123,61 +192,83 @@ inline bool IsSwitchChar(char c)
#endif
}
-/**
- * Return true if the given argument has been manually set
- *
- * @param strArg Argument to get (e.g. "-foo")
- * @return true if the argument has been set
- */
-bool IsArgSet(const std::string& strArg);
-
-/**
- * Return string argument or default value
- *
- * @param strArg Argument to get (e.g. "-foo")
- * @param default (e.g. "1")
- * @return command-line argument or default value
- */
-std::string GetArg(const std::string& strArg, const std::string& strDefault);
-
-/**
- * Return integer argument or default value
- *
- * @param strArg Argument to get (e.g. "-foo")
- * @param default (e.g. 1)
- * @return command-line argument (0 if invalid number) or default value
- */
-int64_t GetArg(const std::string& strArg, int64_t nDefault);
-
-/**
- * Return boolean argument or default value
- *
- * @param strArg Argument to get (e.g. "-foo")
- * @param default (true or false)
- * @return command-line argument or default value
- */
-bool GetBoolArg(const std::string& strArg, bool fDefault);
-
-/**
- * Set an argument if it doesn't already have a value
- *
- * @param strArg Argument to set (e.g. "-foo")
- * @param strValue Value (e.g. "1")
- * @return true if argument gets set, false if it already had a value
- */
-bool SoftSetArg(const std::string& strArg, const std::string& strValue);
-
-/**
- * Set a boolean argument if it doesn't already have a value
- *
- * @param strArg Argument to set (e.g. "-foo")
- * @param fValue Value (e.g. false)
- * @return true if argument gets set, false if it already had a value
- */
-bool SoftSetBoolArg(const std::string& strArg, bool fValue);
+class ArgsManager
+{
+protected:
+ mutable CCriticalSection cs_args;
+ std::map<std::string, std::string> mapArgs;
+ std::map<std::string, std::vector<std::string>> mapMultiArgs;
+public:
+ void ParseParameters(int argc, const char*const argv[]);
+ void ReadConfigFile(const std::string& confPath);
+
+ /**
+ * Return a vector of strings of the given argument
+ *
+ * @param strArg Argument to get (e.g. "-foo")
+ * @return command-line arguments
+ */
+ std::vector<std::string> GetArgs(const std::string& strArg) const;
+
+ /**
+ * Return true if the given argument has been manually set
+ *
+ * @param strArg Argument to get (e.g. "-foo")
+ * @return true if the argument has been set
+ */
+ bool IsArgSet(const std::string& strArg) const;
+
+ /**
+ * Return string argument or default value
+ *
+ * @param strArg Argument to get (e.g. "-foo")
+ * @param strDefault (e.g. "1")
+ * @return command-line argument or default value
+ */
+ std::string GetArg(const std::string& strArg, const std::string& strDefault) const;
+
+ /**
+ * Return integer argument or default value
+ *
+ * @param strArg Argument to get (e.g. "-foo")
+ * @param nDefault (e.g. 1)
+ * @return command-line argument (0 if invalid number) or default value
+ */
+ int64_t GetArg(const std::string& strArg, int64_t nDefault) const;
+
+ /**
+ * Return boolean argument or default value
+ *
+ * @param strArg Argument to get (e.g. "-foo")
+ * @param fDefault (true or false)
+ * @return command-line argument or default value
+ */
+ bool GetBoolArg(const std::string& strArg, bool fDefault) const;
+
+ /**
+ * Set an argument if it doesn't already have a value
+ *
+ * @param strArg Argument to set (e.g. "-foo")
+ * @param strValue Value (e.g. "1")
+ * @return true if argument gets set, false if it already had a value
+ */
+ bool SoftSetArg(const std::string& strArg, const std::string& strValue);
+
+ /**
+ * Set a boolean argument if it doesn't already have a value
+ *
+ * @param strArg Argument to set (e.g. "-foo")
+ * @param fValue Value (e.g. false)
+ * @return true if argument gets set, false if it already had a value
+ */
+ bool SoftSetBoolArg(const std::string& strArg, bool fValue);
+
+ // Forces an arg setting. Called by SoftSetArg() if the arg hasn't already
+ // been set. Also called directly in testing.
+ void ForceSetArg(const std::string& strArg, const std::string& strValue);
+};
-// Forces a arg setting, used only in testing
-void ForceSetArg(const std::string& strArg, const std::string& strValue);
+extern ArgsManager gArgs;
/**
* Format a string to be used as group of options in help messages
@@ -228,7 +319,7 @@ template <typename Callable> void TraceThread(const char* name, Callable func)
throw;
}
catch (...) {
- PrintExceptionContinue(NULL, name);
+ PrintExceptionContinue(nullptr, name);
throw;
}
}
diff --git a/src/utilmoneystr.cpp b/src/utilmoneystr.cpp
index bebe56130d..6e6e33184e 100644
--- a/src/utilmoneystr.cpp
+++ b/src/utilmoneystr.cpp
@@ -9,8 +9,6 @@
#include "tinyformat.h"
#include "utilstrencodings.h"
-using namespace std;
-
std::string FormatMoney(const CAmount& n)
{
// Note: not using straight sprintf here because we do NOT want
@@ -18,7 +16,7 @@ std::string FormatMoney(const CAmount& n)
int64_t n_abs = (n > 0 ? n : -n);
int64_t quotient = n_abs/COIN;
int64_t remainder = n_abs%COIN;
- string str = strprintf("%d.%08d", quotient, remainder);
+ std::string str = strprintf("%d.%08d", quotient, remainder);
// Right-trim excess zeros before the decimal point:
int nTrim = 0;
@@ -33,14 +31,14 @@ std::string FormatMoney(const CAmount& n)
}
-bool ParseMoney(const string& str, CAmount& nRet)
+bool ParseMoney(const std::string& str, CAmount& nRet)
{
return ParseMoney(str.c_str(), nRet);
}
bool ParseMoney(const char* pszIn, CAmount& nRet)
{
- string strWhole;
+ std::string strWhole;
int64_t nUnits = 0;
const char* p = pszIn;
while (isspace(*p))
diff --git a/src/utilmoneystr.h b/src/utilmoneystr.h
index 5839b07344..bc885ee167 100644
--- a/src/utilmoneystr.h
+++ b/src/utilmoneystr.h
@@ -14,6 +14,9 @@
#include "amount.h"
+/* Do not use these functions to represent or parse monetary amounts to or from
+ * JSON but use AmountFromValue and ValueFromAmount for that.
+ */
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 025040c43a..741680e93f 100644
--- a/src/utilstrencodings.cpp
+++ b/src/utilstrencodings.cpp
@@ -12,19 +12,18 @@
#include <errno.h>
#include <limits>
-using namespace std;
+static const std::string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
-static const string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
-
-static const string SAFE_CHARS[] =
+static const std::string SAFE_CHARS[] =
{
CHARS_ALPHA_NUM + " .,;-_/:?@()", // SAFE_CHARS_DEFAULT
- CHARS_ALPHA_NUM + " .,;-_?@" // SAFE_CHARS_UA_COMMENT
+ CHARS_ALPHA_NUM + " .,;-_?@", // SAFE_CHARS_UA_COMMENT
+ CHARS_ALPHA_NUM + ".-_", // SAFE_CHARS_FILENAME
};
-string SanitizeString(const string& str, int rule)
+std::string SanitizeString(const std::string& str, int rule)
{
- string strResult;
+ std::string strResult;
for (std::string::size_type i = 0; i < str.size(); i++)
{
if (SAFE_CHARS[rule].find(str[i]) != std::string::npos)
@@ -56,7 +55,7 @@ signed char HexDigit(char c)
return p_util_hexdigit[(unsigned char)c];
}
-bool IsHex(const string& str)
+bool IsHex(const std::string& str)
{
for(std::string::const_iterator it(str.begin()); it != str.end(); ++it)
{
@@ -66,10 +65,23 @@ bool IsHex(const string& str)
return (str.size() > 0) && (str.size()%2 == 0);
}
-vector<unsigned char> ParseHex(const char* psz)
+bool IsHexNumber(const std::string& str)
+{
+ size_t starting_location = 0;
+ if (str.size() > 2 && *str.begin() == '0' && *(str.begin()+1) == 'x') {
+ starting_location = 2;
+ }
+ for (auto c : str.substr(starting_location)) {
+ if (HexDigit(c) < 0) return false;
+ }
+ // Return false for empty string or "0x".
+ return (str.size() > starting_location);
+}
+
+std::vector<unsigned char> ParseHex(const char* psz)
{
// convert hex dump to vector
- vector<unsigned char> vch;
+ std::vector<unsigned char> vch;
while (true)
{
while (isspace(*psz))
@@ -87,16 +99,35 @@ vector<unsigned char> ParseHex(const char* psz)
return vch;
}
-vector<unsigned char> ParseHex(const string& str)
+std::vector<unsigned char> ParseHex(const std::string& str)
{
return ParseHex(str.c_str());
}
-string EncodeBase64(const unsigned char* pch, size_t len)
+void SplitHostPort(std::string in, int &portOut, std::string &hostOut) {
+ size_t colon = in.find_last_of(':');
+ // if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator
+ bool fHaveColon = colon != in.npos;
+ bool fBracketed = fHaveColon && (in[0]=='[' && in[colon-1]==']'); // if there is a colon, and in[0]=='[', colon is not 0, so in[colon-1] is safe
+ bool fMultiColon = fHaveColon && (in.find_last_of(':',colon-1) != in.npos);
+ if (fHaveColon && (colon==0 || fBracketed || !fMultiColon)) {
+ int32_t n;
+ if (ParseInt32(in.substr(colon + 1), &n) && n > 0 && n < 0x10000) {
+ in = in.substr(0, colon);
+ portOut = n;
+ }
+ }
+ if (in.size()>0 && in[0] == '[' && in[in.size()-1] == ']')
+ hostOut = in.substr(1, in.size()-2);
+ else
+ hostOut = in;
+}
+
+std::string EncodeBase64(const unsigned char* pch, size_t len)
{
static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- string strRet="";
+ std::string strRet = "";
strRet.reserve((len+2)/3*4);
int mode=0, left=0;
@@ -138,12 +169,12 @@ string EncodeBase64(const unsigned char* pch, size_t len)
return strRet;
}
-string EncodeBase64(const string& str)
+std::string EncodeBase64(const std::string& str)
{
return EncodeBase64((const unsigned char*)str.c_str(), str.size());
}
-vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid)
+std::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid)
{
static const int decode64_table[256] =
{
@@ -165,7 +196,7 @@ vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid)
if (pfInvalid)
*pfInvalid = false;
- vector<unsigned char> vchRet;
+ std::vector<unsigned char> vchRet;
vchRet.reserve(strlen(p)*3/4);
int mode = 0;
@@ -226,17 +257,17 @@ vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid)
return vchRet;
}
-string DecodeBase64(const string& str)
+std::string DecodeBase64(const std::string& str)
{
- vector<unsigned char> vchRet = DecodeBase64(str.c_str());
- return (vchRet.size() == 0) ? string() : string((const char*)&vchRet[0], vchRet.size());
+ std::vector<unsigned char> vchRet = DecodeBase64(str.c_str());
+ return std::string((const char*)vchRet.data(), vchRet.size());
}
-string EncodeBase32(const unsigned char* pch, size_t len)
+std::string EncodeBase32(const unsigned char* pch, size_t len)
{
static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567";
- string strRet="";
+ std::string strRet="";
strRet.reserve((len+4)/5*8);
int mode=0, left=0;
@@ -291,12 +322,12 @@ string EncodeBase32(const unsigned char* pch, size_t len)
return strRet;
}
-string EncodeBase32(const string& str)
+std::string EncodeBase32(const std::string& str)
{
return EncodeBase32((const unsigned char*)str.c_str(), str.size());
}
-vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid)
+std::vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid)
{
static const int decode32_table[256] =
{
@@ -318,7 +349,7 @@ vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid)
if (pfInvalid)
*pfInvalid = false;
- vector<unsigned char> vchRet;
+ std::vector<unsigned char> vchRet;
vchRet.reserve((strlen(p))*5/8);
int mode = 0;
@@ -413,10 +444,10 @@ vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid)
return vchRet;
}
-string DecodeBase32(const string& str)
+std::string DecodeBase32(const std::string& str)
{
- vector<unsigned char> vchRet = DecodeBase32(str.c_str());
- return (vchRet.size() == 0) ? string() : string((const char*)&vchRet[0], vchRet.size());
+ std::vector<unsigned char> vchRet = DecodeBase32(str.c_str());
+ return std::string((const char*)vchRet.data(), vchRet.size());
}
static bool ParsePrechecks(const std::string& str)
@@ -434,11 +465,11 @@ bool ParseInt32(const std::string& str, int32_t *out)
{
if (!ParsePrechecks(str))
return false;
- char *endp = NULL;
+ char *endp = nullptr;
errno = 0; // strtol will not set errno if valid
long int n = strtol(str.c_str(), &endp, 10);
if(out) *out = (int32_t)n;
- // Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow
+ // Note that strtol returns a *long int*, so even if strtol doesn't report an 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.
return endp && *endp == 0 && !errno &&
@@ -450,11 +481,11 @@ bool ParseInt64(const std::string& str, int64_t *out)
{
if (!ParsePrechecks(str))
return false;
- char *endp = NULL;
+ char *endp = nullptr;
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
+ // Note that strtoll returns a *long long int*, so even if strtol doesn't report an 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() &&
@@ -467,11 +498,11 @@ bool ParseUInt32(const std::string& str, uint32_t *out)
return false;
if (str.size() >= 1 && str[0] == '-') // Reject negative values, unfortunately strtoul accepts these by default if they fit in the range
return false;
- char *endp = NULL;
+ char *endp = nullptr;
errno = 0; // strtoul will not set errno if valid
unsigned long int n = strtoul(str.c_str(), &endp, 10);
if(out) *out = (uint32_t)n;
- // Note that strtoul returns a *unsigned long int*, so even if it doesn't report a over/underflow
+ // Note that strtoul returns a *unsigned long int*, so even if it doesn't report an over/underflow
// we still have to check that the returned value is within the range of an *uint32_t*. On 64-bit
// platforms the size of these types may be different.
return endp && *endp == 0 && !errno &&
@@ -484,11 +515,11 @@ bool ParseUInt64(const std::string& str, uint64_t *out)
return false;
if (str.size() >= 1 && str[0] == '-') // Reject negative values, unfortunately strtoull accepts these by default if they fit in the range
return false;
- char *endp = NULL;
+ char *endp = nullptr;
errno = 0; // strtoull will not set errno if valid
unsigned long long int n = strtoull(str.c_str(), &endp, 10);
if(out) *out = (uint64_t)n;
- // Note that strtoull returns a *unsigned long long int*, so even if it doesn't report a over/underflow
+ // Note that strtoull returns a *unsigned long long int*, so even if it doesn't report an over/underflow
// we still have to check that the returned value is within the range of an *uint64_t*.
return endp && *endp == 0 && !errno &&
n <= std::numeric_limits<uint64_t>::max();
@@ -565,7 +596,7 @@ int64_t atoi64(const char* psz)
#ifdef _MSC_VER
return _atoi64(psz);
#else
- return strtoll(psz, NULL, 10);
+ return strtoll(psz, nullptr, 10);
#endif
}
@@ -574,7 +605,7 @@ int64_t atoi64(const std::string& str)
#ifdef _MSC_VER
return _atoi64(str.c_str());
#else
- return strtoll(str.c_str(), NULL, 10);
+ return strtoll(str.c_str(), nullptr, 10);
#endif
}
diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h
index cb6f014fc2..af33f0e5f8 100644
--- a/src/utilstrencodings.h
+++ b/src/utilstrencodings.h
@@ -19,14 +19,12 @@
#define UEND(a) ((unsigned char*)&((&(a))[1]))
#define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0]))
-/** 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>
-
/** Used by SanitizeString() */
enum SafeChars
{
SAFE_CHARS_DEFAULT, //!< The full set of allowed chars
- SAFE_CHARS_UA_COMMENT //!< BIP-0014 subset
+ SAFE_CHARS_UA_COMMENT, //!< BIP-0014 subset
+ SAFE_CHARS_FILENAME, //!< Chars allowed in filenames
};
/**
@@ -40,16 +38,23 @@ 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);
+/* Returns true if each character in str is a hex character, and has an even
+ * number of hex digits.*/
bool IsHex(const std::string& str);
-std::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid = NULL);
+/**
+* Return true if the string is a hex number, optionally prefixed with "0x"
+*/
+bool IsHexNumber(const std::string& str);
+std::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid = nullptr);
std::string DecodeBase64(const std::string& str);
std::string EncodeBase64(const unsigned char* pch, size_t len);
std::string EncodeBase64(const std::string& str);
-std::vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid = NULL);
+std::vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid = nullptr);
std::string DecodeBase32(const std::string& str);
std::string EncodeBase32(const unsigned char* pch, size_t len);
std::string EncodeBase32(const std::string& str);
+void SplitHostPort(std::string in, int &portOut, std::string &hostOut);
std::string i64tostr(int64_t n);
std::string itostr(int n);
int64_t atoi64(const char* psz);
@@ -144,4 +149,28 @@ bool TimingResistantEqual(const T& a, const T& b)
*/
bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out);
+/** Convert from one power-of-2 number base to another. */
+template<int frombits, int tobits, bool pad, typename O, typename I>
+bool ConvertBits(O& out, I it, I end) {
+ size_t acc = 0;
+ size_t bits = 0;
+ constexpr size_t maxv = (1 << tobits) - 1;
+ constexpr size_t max_acc = (1 << (frombits + tobits - 1)) - 1;
+ while (it != end) {
+ acc = ((acc << frombits) | *it) & max_acc;
+ bits += frombits;
+ while (bits >= tobits) {
+ bits -= tobits;
+ out.push_back((acc >> bits) & maxv);
+ }
+ ++it;
+ }
+ if (pad) {
+ if (bits) out.push_back((acc << (tobits - bits)) & maxv);
+ } else if (bits >= frombits || ((acc << (tobits - bits)) & maxv)) {
+ return false;
+ }
+ return true;
+}
+
#endif // BITCOIN_UTILSTRENCODINGS_H
diff --git a/src/utiltime.cpp b/src/utiltime.cpp
index 7c5ee77265..4cc77dbfeb 100644
--- a/src/utiltime.cpp
+++ b/src/utiltime.cpp
@@ -9,25 +9,31 @@
#include "utiltime.h"
+#include <atomic>
+
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread.hpp>
-using namespace std;
-
-static int64_t nMockTime = 0; //!< For unit testing
+static std::atomic<int64_t> nMockTime(0); //!< For unit testing
int64_t GetTime()
{
- if (nMockTime) return nMockTime;
+ int64_t mocktime = nMockTime.load(std::memory_order_relaxed);
+ if (mocktime) return mocktime;
- time_t now = time(NULL);
+ time_t now = time(nullptr);
assert(now > 0);
return now;
}
void SetMockTime(int64_t nMockTimeIn)
{
- nMockTime = nMockTimeIn;
+ nMockTime.store(nMockTimeIn, std::memory_order_relaxed);
+}
+
+int64_t GetMockTime()
+{
+ return nMockTime.load(std::memory_order_relaxed);
}
int64_t GetTimeMillis()
@@ -46,19 +52,16 @@ int64_t GetTimeMicros()
return now;
}
-/** Return a time useful for the debug log */
-int64_t GetLogTimeMicros()
+int64_t GetSystemTimeInSeconds()
{
- if (nMockTime) return nMockTime*1000000;
-
- return GetTimeMicros();
+ return GetTimeMicros()/1000000;
}
void MilliSleep(int64_t n)
{
/**
- * Boost's sleep_for was uninterruptable when backed by nanosleep from 1.50
+ * Boost's sleep_for was uninterruptible when backed by nanosleep from 1.50
* until fixed in 1.52. Use the deprecated sleep method for the broken case.
* See: https://svn.boost.org/trac/boost/ticket/7238
*/
diff --git a/src/utiltime.h b/src/utiltime.h
index b2807267db..8ae8540b89 100644
--- a/src/utiltime.h
+++ b/src/utiltime.h
@@ -9,11 +9,22 @@
#include <stdint.h>
#include <string>
+/**
+ * GetTimeMicros() and GetTimeMillis() both return the system time, but in
+ * different units. GetTime() returns the system time in seconds, but also
+ * supports mocktime, where the time can be specified by the user, eg for
+ * testing (eg with the setmocktime rpc, or -mocktime argument).
+ *
+ * TODO: Rework these functions to be type-safe (so that we don't inadvertently
+ * compare numbers with different units, or compare a mocktime to system time).
+ */
+
int64_t GetTime();
int64_t GetTimeMillis();
int64_t GetTimeMicros();
-int64_t GetLogTimeMicros();
+int64_t GetSystemTimeInSeconds(); // Like GetTime(), but not mockable
void SetMockTime(int64_t nMockTimeIn);
+int64_t GetMockTime();
void MilliSleep(int64_t n);
std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime);
diff --git a/src/validation.cpp b/src/validation.cpp
index 2ad3dadeb6..7f27d8c0bf 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -6,20 +6,26 @@
#include "validation.h"
#include "arith_uint256.h"
+#include "chain.h"
#include "chainparams.h"
#include "checkpoints.h"
#include "checkqueue.h"
#include "consensus/consensus.h"
#include "consensus/merkle.h"
+#include "consensus/tx_verify.h"
#include "consensus/validation.h"
+#include "cuckoocache.h"
+#include "fs.h"
#include "hash.h"
#include "init.h"
#include "policy/fees.h"
#include "policy/policy.h"
+#include "policy/rbf.h"
#include "pow.h"
#include "primitives/block.h"
#include "primitives/transaction.h"
#include "random.h"
+#include "reverse_iterator.h"
#include "script/script.h"
#include "script/sigcache.h"
#include "script/standard.h"
@@ -41,17 +47,15 @@
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/join.hpp>
-#include <boost/filesystem.hpp>
-#include <boost/filesystem/fstream.hpp>
-#include <boost/math/distributions/poisson.hpp>
#include <boost/thread.hpp>
-using namespace std;
-
#if defined(NDEBUG)
# error "Bitcoin cannot be compiled without assertions."
#endif
+#define MICRO 0.000001
+#define MILLI 0.001
+
/**
* Global state
*/
@@ -60,12 +64,12 @@ CCriticalSection cs_main;
BlockMap mapBlockIndex;
CChain chainActive;
-CBlockIndex *pindexBestHeader = NULL;
+CBlockIndex *pindexBestHeader = nullptr;
CWaitableCriticalSection csBestBlock;
CConditionVariable cvBlockChange;
int nScriptCheckThreads = 0;
std::atomic_bool fImporting(false);
-bool fReindex = false;
+std::atomic_bool fReindex(false);
bool fTxIndex = false;
bool fHavePruned = false;
bool fPruneMode = false;
@@ -79,25 +83,27 @@ int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT;
uint256 hashAssumeValid;
+arith_uint256 nMinimumChainWork;
CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
-CTxMemPool mempool(::minRelayTxFee);
+CBlockPolicyEstimator feeEstimator;
+CTxMemPool mempool(&feeEstimator);
static void CheckBlockIndex(const Consensus::Params& consensusParams);
/** Constant stuff for coinbase transactions we create: */
CScript COINBASE_FLAGS;
-const string strMessageMagic = "Bitcoin Signed Message:\n";
+const std::string strMessageMagic = "Bitcoin Signed Message:\n";
// Internal stuff
namespace {
struct CBlockIndexWorkComparator
{
- bool operator()(CBlockIndex *pa, CBlockIndex *pb) const {
+ bool operator()(const CBlockIndex *pa, const CBlockIndex *pb) const {
// First sort by most total work, ...
if (pa->nChainWork > pb->nChainWork) return false;
if (pa->nChainWork < pb->nChainWork) return true;
@@ -123,11 +129,11 @@ namespace {
* as good as our current tip or better. Entries may be failed, though, and pruning nodes may be
* missing the data for the block.
*/
- set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;
+ std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;
/** All pairs A->B, where A (or one of its ancestors) misses transactions, but B has transactions.
* Pruned nodes may have entries where B is missing data.
*/
- multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
+ std::multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
CCriticalSection cs_LastBlockFile;
std::vector<CBlockFileInfo> vinfoBlockFile;
@@ -151,16 +157,16 @@ namespace {
arith_uint256 nLastPreciousChainwork = 0;
/** Dirty block index entries. */
- set<CBlockIndex*> setDirtyBlockIndex;
+ std::set<CBlockIndex*> setDirtyBlockIndex;
/** Dirty block file entries. */
- set<int> setDirtyFileInfo;
+ std::set<int> setDirtyFileInfo;
} // anon namespace
CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator)
{
// Find the first block the caller has in the main chain
- BOOST_FOREACH(const uint256& hash, locator.vHave) {
+ for (const uint256& hash : locator.vHave) {
BlockMap::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end())
{
@@ -175,8 +181,9 @@ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& loc
return chain.Genesis();
}
-CCoinsViewCache *pcoinsTip = NULL;
-CBlockTreeDB *pblocktree = NULL;
+CCoinsViewDB *pcoinsdbview = nullptr;
+CCoinsViewCache *pcoinsTip = nullptr;
+CBlockTreeDB *pblocktree = nullptr;
enum FlushStateMode {
FLUSH_STATE_NONE,
@@ -186,21 +193,11 @@ enum FlushStateMode {
};
// See definition for documentation
-bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode, int nManualPruneHeight=0);
-void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight);
-
-bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
-{
- if (tx.nLockTime == 0)
- return true;
- if ((int64_t)tx.nLockTime < ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime))
- return true;
- for (const auto& txin : tx.vin) {
- if (!(txin.nSequence == CTxIn::SEQUENCE_FINAL))
- return false;
- }
- return true;
-}
+static bool FlushStateToDisk(const CChainParams& chainParams, CValidationState &state, FlushStateMode mode, int nManualPruneHeight=0);
+static void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight);
+static void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight);
+bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks = nullptr);
+static FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly = false);
bool CheckFinalTx(const CTransaction &tx, int flags)
{
@@ -222,7 +219,7 @@ bool CheckFinalTx(const CTransaction &tx, int flags)
// IsFinalTx() with one more than chainActive.Height().
const int nBlockHeight = chainActive.Height() + 1;
- // BIP113 will require that time-locked transactions have nLockTime set to
+ // BIP113 requires that time-locked transactions have nLockTime set to
// less than the median time of the previous block they're contained in.
// When the next block is created its previous block will be the current
// chain tip, so we use that to calculate the median time passed to
@@ -234,89 +231,6 @@ bool CheckFinalTx(const CTransaction &tx, int flags)
return IsFinalTx(tx, nBlockHeight, nBlockTime);
}
-/**
- * Calculates the block height and previous block's median time past at
- * which the transaction will be considered final in the context of BIP 68.
- * Also removes from the vector of input heights any entries which did not
- * correspond to sequence locked inputs as they do not affect the calculation.
- */
-static std::pair<int, int64_t> CalculateSequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeights, const CBlockIndex& block)
-{
- assert(prevHeights->size() == tx.vin.size());
-
- // Will be set to the equivalent height- and time-based nLockTime
- // values that would be necessary to satisfy all relative lock-
- // time constraints given our view of block chain history.
- // The semantics of nLockTime are the last invalid height/time, so
- // use -1 to have the effect of any height or time being valid.
- int nMinHeight = -1;
- int64_t nMinTime = -1;
-
- // tx.nVersion is signed integer so requires cast to unsigned otherwise
- // we would be doing a signed comparison and half the range of nVersion
- // wouldn't support BIP 68.
- bool fEnforceBIP68 = static_cast<uint32_t>(tx.nVersion) >= 2
- && flags & LOCKTIME_VERIFY_SEQUENCE;
-
- // Do not enforce sequence numbers as a relative lock time
- // unless we have been instructed to
- if (!fEnforceBIP68) {
- return std::make_pair(nMinHeight, nMinTime);
- }
-
- for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
- const CTxIn& txin = tx.vin[txinIndex];
-
- // Sequence numbers with the most significant bit set are not
- // treated as relative lock-times, nor are they given any
- // consensus-enforced meaning at this point.
- if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) {
- // The height of this input is not relevant for sequence locks
- (*prevHeights)[txinIndex] = 0;
- continue;
- }
-
- int nCoinHeight = (*prevHeights)[txinIndex];
-
- if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) {
- int64_t nCoinTime = block.GetAncestor(std::max(nCoinHeight-1, 0))->GetMedianTimePast();
- // NOTE: Subtract 1 to maintain nLockTime semantics
- // BIP 68 relative lock times have the semantics of calculating
- // the first block or time at which the transaction would be
- // valid. When calculating the effective block time or height
- // for the entire transaction, we switch to using the
- // semantics of nLockTime which is the last invalid block
- // time or height. Thus we subtract 1 from the calculated
- // time or height.
-
- // Time-based relative lock-times are measured from the
- // smallest allowed timestamp of the block containing the
- // txout being spent, which is the median time past of the
- // block prior.
- nMinTime = std::max(nMinTime, nCoinTime + (int64_t)((txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) << CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) - 1);
- } else {
- nMinHeight = std::max(nMinHeight, nCoinHeight + (int)(txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) - 1);
- }
- }
-
- return std::make_pair(nMinHeight, nMinTime);
-}
-
-static bool EvaluateSequenceLocks(const CBlockIndex& block, std::pair<int, int64_t> lockPair)
-{
- assert(block.pprev);
- int64_t nBlockTime = block.pprev->GetMedianTimePast();
- if (lockPair.first >= block.nHeight || lockPair.second >= nBlockTime)
- return false;
-
- return true;
-}
-
-bool SequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeights, const CBlockIndex& block)
-{
- return EvaluateSequenceLocks(block, CalculateSequenceLocks(tx, flags, prevHeights, block));
-}
-
bool TestLockPointValidity(const LockPoints* lp)
{
AssertLockHeld(cs_main);
@@ -341,6 +255,8 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool
AssertLockHeld(mempool.cs);
CBlockIndex* tip = chainActive.Tip();
+ assert(tip != nullptr);
+
CBlockIndex index;
index.pprev = tip;
// CheckSequenceLocks() uses chainActive.Height()+1 to evaluate
@@ -364,15 +280,15 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool
prevheights.resize(tx.vin.size());
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
const CTxIn& txin = tx.vin[txinIndex];
- CCoins coins;
- if (!viewMemPool.GetCoins(txin.prevout.hash, coins)) {
+ Coin coin;
+ if (!viewMemPool.GetCoin(txin.prevout, coin)) {
return error("%s: Missing input", __func__);
}
- if (coins.nHeight == MEMPOOL_HEIGHT) {
+ if (coin.nHeight == MEMPOOL_HEIGHT) {
// Assume all mempool transaction confirm in the next block
prevheights[txinIndex] = tip->nHeight + 1;
} else {
- prevheights[txinIndex] = coins.nHeight;
+ prevheights[txinIndex] = coin.nHeight;
}
}
lockPair = CalculateSequenceLocks(tx, flags, &prevheights, index);
@@ -393,7 +309,7 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool
// lock on a mempool input, so we can use the return value of
// CheckSequenceLocks to indicate the LockPoints validity
int maxInputHeight = 0;
- BOOST_FOREACH(int height, prevheights) {
+ for (int height : prevheights) {
// Can ignore mempool inputs since we'll fail if they had non-zero locks
if (height != tip->nHeight+1) {
maxInputHeight = std::max(maxInputHeight, height);
@@ -405,116 +321,18 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool
return EvaluateSequenceLocks(index, lockPair);
}
+// Returns the script flags which should be checked for a given block
+static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consensus::Params& chainparams);
-unsigned int GetLegacySigOpCount(const CTransaction& tx)
-{
- unsigned int nSigOps = 0;
- for (const auto& txin : tx.vin)
- {
- nSigOps += txin.scriptSig.GetSigOpCount(false);
- }
- for (const auto& txout : tx.vout)
- {
- nSigOps += txout.scriptPubKey.GetSigOpCount(false);
- }
- return nSigOps;
-}
-
-unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs)
-{
- if (tx.IsCoinBase())
- return 0;
-
- unsigned int nSigOps = 0;
- for (unsigned int i = 0; i < tx.vin.size(); i++)
- {
- const CTxOut &prevout = inputs.GetOutputFor(tx.vin[i]);
- if (prevout.scriptPubKey.IsPayToScriptHash())
- nSigOps += prevout.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig);
- }
- return nSigOps;
-}
-
-int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, int flags)
-{
- int64_t nSigOps = GetLegacySigOpCount(tx) * WITNESS_SCALE_FACTOR;
-
- if (tx.IsCoinBase())
- return nSigOps;
-
- if (flags & SCRIPT_VERIFY_P2SH) {
- nSigOps += GetP2SHSigOpCount(tx, inputs) * WITNESS_SCALE_FACTOR;
- }
-
- for (unsigned int i = 0; i < tx.vin.size(); i++)
- {
- const CTxOut &prevout = inputs.GetOutputFor(tx.vin[i]);
- nSigOps += CountWitnessSigOps(tx.vin[i].scriptSig, prevout.scriptPubKey, &tx.vin[i].scriptWitness, flags);
- }
- return nSigOps;
-}
-
-
-
-
-
-bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fCheckDuplicateInputs)
-{
- // Basic checks that don't depend on any context
- if (tx.vin.empty())
- return state.DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty");
- if (tx.vout.empty())
- return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty");
- // Size limits (this doesn't take the witness into account, as that hasn't been checked for malleability)
- if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) > MAX_BLOCK_BASE_SIZE)
- return state.DoS(100, false, REJECT_INVALID, "bad-txns-oversize");
-
- // Check for negative or overflow output values
- CAmount nValueOut = 0;
- for (const auto& txout : tx.vout)
- {
- if (txout.nValue < 0)
- return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-negative");
- if (txout.nValue > MAX_MONEY)
- return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-toolarge");
- nValueOut += txout.nValue;
- if (!MoneyRange(nValueOut))
- return state.DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge");
- }
-
- // Check for duplicate inputs - note that this check is slow so we skip it in CheckBlock
- if (fCheckDuplicateInputs) {
- set<COutPoint> vInOutPoints;
- for (const auto& txin : tx.vin)
- {
- if (!vInOutPoints.insert(txin.prevout).second)
- return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-duplicate");
- }
- }
-
- if (tx.IsCoinBase())
- {
- if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100)
- return state.DoS(100, false, REJECT_INVALID, "bad-cb-length");
- }
- else
- {
- for (const auto& txin : tx.vin)
- if (txin.prevout.IsNull())
- return state.DoS(10, false, REJECT_INVALID, "bad-txns-prevout-null");
- }
-
- return true;
-}
-
-void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age) {
+static void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age) {
int expired = pool.Expire(GetTime() - age);
- if (expired != 0)
- LogPrint("mempool", "Expired %i transactions from the memory pool\n", expired);
+ if (expired != 0) {
+ LogPrint(BCLog::MEMPOOL, "Expired %i transactions from the memory pool\n", expired);
+ }
- std::vector<uint256> vNoSpendsRemaining;
+ std::vector<COutPoint> vNoSpendsRemaining;
pool.TrimToSize(limit, &vNoSpendsRemaining);
- BOOST_FOREACH(const uint256& removed, vNoSpendsRemaining)
+ for (const COutPoint& removed : vNoSpendsRemaining)
pcoinsTip->Uncache(removed);
}
@@ -539,9 +357,97 @@ static bool IsCurrentForFeeEstimation()
return true;
}
-bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const CTransactionRef& ptx, bool fLimitFree,
- bool* pfMissingInputs, int64_t nAcceptTime, bool fOverrideMempoolLimit, const CAmount& nAbsurdFee,
- std::vector<uint256>& vHashTxnToUncache)
+/* Make mempool consistent after a reorg, by re-adding or recursively erasing
+ * disconnected block transactions from the mempool, and also removing any
+ * other transactions from the mempool that are no longer valid given the new
+ * tip/height.
+ *
+ * Note: we assume that disconnectpool only contains transactions that are NOT
+ * confirmed in the current chain nor already in the mempool (otherwise,
+ * in-mempool descendants of such transactions would be removed).
+ *
+ * Passing fAddToMempool=false will skip trying to add the transactions back,
+ * and instead just erase from the mempool as needed.
+ */
+
+void UpdateMempoolForReorg(DisconnectedBlockTransactions &disconnectpool, bool fAddToMempool)
+{
+ AssertLockHeld(cs_main);
+ std::vector<uint256> vHashUpdate;
+ // disconnectpool's insertion_order index sorts the entries from
+ // oldest to newest, but the oldest entry will be the last tx from the
+ // latest mined block that was disconnected.
+ // Iterate disconnectpool in reverse, so that we add transactions
+ // back to the mempool starting with the earliest transaction that had
+ // been previously seen in a block.
+ auto it = disconnectpool.queuedTx.get<insertion_order>().rbegin();
+ while (it != disconnectpool.queuedTx.get<insertion_order>().rend()) {
+ // ignore validation errors in resurrected transactions
+ CValidationState stateDummy;
+ if (!fAddToMempool || (*it)->IsCoinBase() ||
+ !AcceptToMemoryPool(mempool, stateDummy, *it, nullptr /* pfMissingInputs */,
+ nullptr /* plTxnReplaced */, true /* bypass_limits */, 0 /* nAbsurdFee */)) {
+ // If the transaction doesn't make it in to the mempool, remove any
+ // transactions that depend on it (which would now be orphans).
+ mempool.removeRecursive(**it, MemPoolRemovalReason::REORG);
+ } else if (mempool.exists((*it)->GetHash())) {
+ vHashUpdate.push_back((*it)->GetHash());
+ }
+ ++it;
+ }
+ disconnectpool.queuedTx.clear();
+ // 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
+ // the disconnectpool that were added back and cleans up the mempool state.
+ mempool.UpdateTransactionsFromBlock(vHashUpdate);
+
+ // We also need to remove any now-immature transactions
+ mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS);
+ // Re-limit mempool size, in case we added any transactions
+ LimitMempoolSize(mempool, gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);
+}
+
+// Used to avoid mempool polluting consensus critical paths if CCoinsViewMempool
+// were somehow broken and returning the wrong scriptPubKeys
+static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, CTxMemPool& pool,
+ unsigned int flags, bool cacheSigStore, PrecomputedTransactionData& txdata) {
+ AssertLockHeld(cs_main);
+
+ // pool.cs should be locked already, but go ahead and re-take the lock here
+ // to enforce that mempool doesn't change between when we check the view
+ // and when we actually call through to CheckInputs
+ LOCK(pool.cs);
+
+ assert(!tx.IsCoinBase());
+ for (const CTxIn& txin : tx.vin) {
+ const Coin& coin = view.AccessCoin(txin.prevout);
+
+ // At this point we haven't actually checked if the coins are all
+ // available (or shouldn't assume we have, since CheckInputs does).
+ // So we just return failure if the inputs are not available here,
+ // and then only have to check equivalence for available inputs.
+ if (coin.IsSpent()) return false;
+
+ const CTransactionRef& txFrom = pool.get(txin.prevout.hash);
+ if (txFrom) {
+ assert(txFrom->GetHash() == txin.prevout.hash);
+ assert(txFrom->vout.size() > txin.prevout.n);
+ assert(txFrom->vout[txin.prevout.n] == coin.out);
+ } else {
+ const Coin& coinFromDisk = pcoinsTip->AccessCoin(txin.prevout);
+ assert(!coinFromDisk.IsSpent());
+ assert(coinFromDisk.out == coin.out);
+ }
+ }
+
+ return CheckInputs(tx, state, view, true, flags, cacheSigStore, true, txdata);
+}
+
+static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool& pool, CValidationState& state, const CTransactionRef& ptx,
+ bool* pfMissingInputs, int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,
+ bool bypass_limits, const CAmount& nAbsurdFee, std::vector<COutPoint>& coins_to_uncache)
{
const CTransaction& tx = *ptx;
const uint256 hash = tx.GetHash();
@@ -557,13 +463,13 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
return state.DoS(100, false, REJECT_INVALID, "coinbase");
// Reject transactions with witness before segregated witness activates (override with -prematurewitness)
- bool witnessEnabled = IsWitnessEnabled(chainActive.Tip(), Params().GetConsensus());
- if (!GetBoolArg("-prematurewitness",false) && tx.HasWitness() && !witnessEnabled) {
+ bool witnessEnabled = IsWitnessEnabled(chainActive.Tip(), chainparams.GetConsensus());
+ if (!gArgs.GetBoolArg("-prematurewitness", false) && tx.HasWitness() && !witnessEnabled) {
return state.DoS(0, false, REJECT_NONSTANDARD, "no-witness-yet", true);
}
// Rather not work on nonstandard transactions (unless -testnet/-regtest)
- string reason;
+ std::string reason;
if (fRequireStandard && !IsStandardTx(tx, reason, witnessEnabled))
return state.DoS(0, false, REJECT_NONSTANDARD, reason);
@@ -574,14 +480,15 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
return state.DoS(0, false, REJECT_NONSTANDARD, "non-final");
// is it already in the memory pool?
- if (pool.exists(hash))
- return state.Invalid(false, REJECT_ALREADY_KNOWN, "txn-already-in-mempool");
+ if (pool.exists(hash)) {
+ return state.Invalid(false, REJECT_DUPLICATE, "txn-already-in-mempool");
+ }
// Check for conflicts with in-memory transactions
- set<uint256> setConflicts;
+ std::set<uint256> setConflicts;
{
LOCK(pool.cs); // protect pool.mapNextTx
- BOOST_FOREACH(const CTxIn &txin, tx.vin)
+ for (const CTxIn &txin : tx.vin)
{
auto itConflicting = pool.mapNextTx.find(txin.prevout);
if (itConflicting != pool.mapNextTx.end())
@@ -590,9 +497,9 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
if (!setConflicts.count(ptxConflicting->GetHash()))
{
// Allow opt-out of transaction replacement by setting
- // nSequence >= maxint-1 on all inputs.
+ // nSequence > MAX_BIP125_RBF_SEQUENCE (SEQUENCE_FINAL-2) on all inputs.
//
- // maxint-1 is picked to still allow use of nLockTime by
+ // SEQUENCE_FINAL-1 is picked to still allow use of nLockTime by
// non-replaceable transactions. All inputs rather than just one
// is for the sake of multi-party protocols, where we don't
// want a single party to be able to disable replacement.
@@ -604,17 +511,18 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
bool fReplacementOptOut = true;
if (fEnableReplacement)
{
- BOOST_FOREACH(const CTxIn &_txin, ptxConflicting->vin)
+ for (const CTxIn &_txin : ptxConflicting->vin)
{
- if (_txin.nSequence < std::numeric_limits<unsigned int>::max()-1)
+ if (_txin.nSequence <= MAX_BIP125_RBF_SEQUENCE)
{
fReplacementOptOut = false;
break;
}
}
}
- if (fReplacementOptOut)
- return state.Invalid(false, REJECT_CONFLICT, "txn-mempool-conflict");
+ if (fReplacementOptOut) {
+ return state.Invalid(false, REJECT_DUPLICATE, "txn-mempool-conflict");
+ }
setConflicts.insert(ptxConflicting->GetHash());
}
@@ -633,31 +541,27 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
CCoinsViewMemPool viewMemPool(pcoinsTip, pool);
view.SetBackend(viewMemPool);
- // do we already have it?
- bool fHadTxInCache = pcoinsTip->HaveCoinsInCache(hash);
- if (view.HaveCoins(hash)) {
- if (!fHadTxInCache)
- vHashTxnToUncache.push_back(hash);
- 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),
- // and only helps with filling in pfMissingInputs (to determine missing vs spent).
- BOOST_FOREACH(const CTxIn txin, tx.vin) {
- if (!pcoinsTip->HaveCoinsInCache(txin.prevout.hash))
- vHashTxnToUncache.push_back(txin.prevout.hash);
- if (!view.HaveCoins(txin.prevout.hash)) {
- if (pfMissingInputs)
+ for (const CTxIn txin : tx.vin) {
+ if (!pcoinsTip->HaveCoinInCache(txin.prevout)) {
+ coins_to_uncache.push_back(txin.prevout);
+ }
+ if (!view.HaveCoin(txin.prevout)) {
+ // Are inputs missing because we already have the tx?
+ for (size_t out = 0; out < tx.vout.size(); out++) {
+ // Optimistically just do efficient check of cache for outputs
+ if (pcoinsTip->HaveCoinInCache(COutPoint(hash, out))) {
+ return state.Invalid(false, REJECT_DUPLICATE, "txn-already-known");
+ }
+ }
+ // Otherwise assume this might be an orphan tx for which we just haven't seen parents yet
+ if (pfMissingInputs) {
*pfMissingInputs = true;
+ }
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(false, REJECT_DUPLICATE, "bad-txns-inputs-spent");
-
// Bring the best block into scope
view.GetBestBlock();
@@ -689,25 +593,21 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
CAmount nFees = nValueIn-nValueOut;
// nModifiedFees includes any fee deltas from PrioritiseTransaction
CAmount nModifiedFees = nFees;
- double nPriorityDummy = 0;
- pool.ApplyDeltas(hash, nPriorityDummy, nModifiedFees);
-
- CAmount inChainInputValue;
- double dPriority = view.GetPriority(tx, chainActive.Height(), inChainInputValue);
+ pool.ApplyDelta(hash, nModifiedFees);
// Keep track of transactions that spend a coinbase, which we re-scan
// during reorgs to ensure COINBASE_MATURITY is still met.
bool fSpendsCoinbase = false;
- BOOST_FOREACH(const CTxIn &txin, tx.vin) {
- const CCoins *coins = view.AccessCoins(txin.prevout.hash);
- if (coins->IsCoinBase()) {
+ for (const CTxIn &txin : tx.vin) {
+ const Coin &coin = view.AccessCoin(txin.prevout);
+ if (coin.IsCoinBase()) {
fSpendsCoinbase = true;
break;
}
}
- CTxMemPoolEntry entry(ptx, nFees, nAcceptTime, dPriority, chainActive.Height(),
- inChainInputValue, fSpendsCoinbase, nSigOpsCost, lp);
+ CTxMemPoolEntry entry(ptx, nFees, nAcceptTime, chainActive.Height(),
+ fSpendsCoinbase, nSigOpsCost, lp);
unsigned int nSize = entry.GetTxSize();
// Check that the transaction doesn't have an excessive number of
@@ -719,35 +619,14 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
return state.DoS(0, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops", false,
strprintf("%d", nSigOpsCost));
- CAmount mempoolRejectFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize);
- if (mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) {
+ CAmount mempoolRejectFee = pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize);
+ if (!bypass_limits && mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) {
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, strprintf("%d < %d", nFees, mempoolRejectFee));
- } else if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && nModifiedFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(entry.GetPriority(chainActive.Height() + 1))) {
- // Require that free transactions have sufficient priority to be mined in the next block.
- return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority");
}
- // Continuously rate-limit free (really, very-low-fee) transactions
- // This mitigates 'penny-flooding' -- sending thousands of free transactions just to
- // be annoying or make others' transactions take longer to confirm.
- if (fLimitFree && nModifiedFees < ::minRelayTxFee.GetFee(nSize))
- {
- static CCriticalSection csFreeLimiter;
- static double dFreeCount;
- static int64_t nLastTime;
- int64_t nNow = GetTime();
-
- LOCK(csFreeLimiter);
-
- // Use an exponentially decaying ~10-minute window:
- dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
- nLastTime = nNow;
- // -limitfreerelay unit is thousand-bytes-per-minute
- // At default rate it would take over a month to fill 1GB
- if (dFreeCount + nSize >= GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) * 10 * 1000)
- return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "rate limited free transaction");
- LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
- dFreeCount += nSize;
+ // No transactions are allowed below minRelayTxFee except from disconnected blocks
+ if (!bypass_limits && nModifiedFees < ::minRelayTxFee.GetFee(nSize)) {
+ return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "min relay fee not met");
}
if (nAbsurdFee && nFees > nAbsurdFee)
@@ -757,10 +636,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// 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;
+ size_t nLimitAncestors = gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT);
+ size_t nLimitAncestorSize = gArgs.GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000;
+ size_t nLimitDescendants = gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT);
+ size_t nLimitDescendantSize = gArgs.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);
@@ -770,7 +649,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// that we have the set of all ancestors we can detect this
// pathological case by making sure setConflicts and setAncestors don't
// intersect.
- BOOST_FOREACH(CTxMemPool::txiter ancestorIt, setAncestors)
+ for (CTxMemPool::txiter ancestorIt : setAncestors)
{
const uint256 &hashAncestor = ancestorIt->GetTx().GetHash();
if (setConflicts.count(hashAncestor))
@@ -794,13 +673,14 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// subsequent RemoveStaged() and addUnchecked() calls don't guarantee
// mempool consistency for us.
LOCK(pool.cs);
- if (setConflicts.size())
+ const bool fReplacementTransaction = setConflicts.size();
+ if (fReplacementTransaction)
{
CFeeRate newFeeRate(nModifiedFees, nSize);
- set<uint256> setConflictsParents;
+ std::set<uint256> setConflictsParents;
const int maxDescendantsToVisit = 100;
CTxMemPool::setEntries setIterConflicting;
- BOOST_FOREACH(const uint256 &hashConflicting, setConflicts)
+ for (const uint256 &hashConflicting : setConflicts)
{
CTxMemPool::txiter mi = pool.mapTx.find(hashConflicting);
if (mi == pool.mapTx.end())
@@ -836,7 +716,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
oldFeeRate.ToString()));
}
- BOOST_FOREACH(const CTxIn &txin, mi->GetTx().vin)
+ for (const CTxIn &txin : mi->GetTx().vin)
{
setConflictsParents.insert(txin.prevout.hash);
}
@@ -849,10 +729,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
if (nConflictingCount <= maxDescendantsToVisit) {
// If not too many to replace, then calculate the set of
// transactions that would have to be evicted
- BOOST_FOREACH(CTxMemPool::txiter it, setIterConflicting) {
+ for (CTxMemPool::txiter it : setIterConflicting) {
pool.CalculateDescendants(it, allConflicting);
}
- BOOST_FOREACH(CTxMemPool::txiter it, allConflicting) {
+ for (CTxMemPool::txiter it : allConflicting) {
nConflictingFees += it->GetModifiedFee();
nConflictingSize += it->GetTxSize();
}
@@ -898,109 +778,137 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// Finally in addition to paying more fees than the conflicts the
// new transaction must pay for its own bandwidth.
CAmount nDeltaFees = nModifiedFees - nConflictingFees;
- if (nDeltaFees < ::minRelayTxFee.GetFee(nSize))
+ if (nDeltaFees < ::incrementalRelayFee.GetFee(nSize))
{
return state.DoS(0, false,
REJECT_INSUFFICIENTFEE, "insufficient fee", false,
strprintf("rejecting replacement %s, not enough additional fees to relay; %s < %s",
hash.ToString(),
FormatMoney(nDeltaFees),
- FormatMoney(::minRelayTxFee.GetFee(nSize))));
+ FormatMoney(::incrementalRelayFee.GetFee(nSize))));
}
}
unsigned int scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS;
- if (!Params().RequireStandard()) {
- scriptVerifyFlags = GetArg("-promiscuousmempoolflags", scriptVerifyFlags);
+ if (!chainparams.RequireStandard()) {
+ scriptVerifyFlags = gArgs.GetArg("-promiscuousmempoolflags", scriptVerifyFlags);
}
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
PrecomputedTransactionData txdata(tx);
- if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true, txdata)) {
+ if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true, false, txdata)) {
// SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
// need to turn both off, and compare against just turning off CLEANSTACK
// to see if the failure is specifically due to witness validation.
- if (!tx.HasWitness() && CheckInputs(tx, state, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, txdata) &&
- !CheckInputs(tx, state, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, txdata)) {
+ CValidationState stateDummy; // Want reported failures to be from first CheckInputs
+ if (!tx.HasWitness() && CheckInputs(tx, stateDummy, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, false, txdata) &&
+ !CheckInputs(tx, stateDummy, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, false, txdata)) {
// Only the witness is missing, so the transaction itself may be fine.
state.SetCorruptionPossible();
}
- return false;
+ return false; // state filled in by CheckInputs
}
- // Check again against just the consensus-critical mandatory script
- // verification flags, in case of bugs in the standard flags that cause
+ // Check again against the current block tip's script verification
+ // flags to cache our script execution flags. This is, of course,
+ // useless if the next block has different script flags from the
+ // previous one, but because the cache tracks script flags for us it
+ // will auto-invalidate and we'll just have a few blocks of extra
+ // misses on soft-fork activation.
+ //
+ // This is also useful in case of bugs in the standard flags that cause
// transactions to pass as valid when they're actually invalid. For
// instance the STRICTENC flag was incorrectly allowing certain
// CHECKSIG NOT scripts to pass, even though they were invalid.
//
// There is a similar check in CreateNewBlock() to prevent creating
- // invalid blocks, however allowing such transactions into the mempool
- // can be exploited as a DoS attack.
- if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata))
+ // invalid blocks (using TestBlockValidity), however allowing such
+ // transactions into the mempool can be exploited as a DoS attack.
+ unsigned int currentBlockScriptVerifyFlags = GetBlockScriptFlags(chainActive.Tip(), Params().GetConsensus());
+ if (!CheckInputsFromMempoolAndCache(tx, state, view, pool, currentBlockScriptVerifyFlags, true, txdata))
{
- return error("%s: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s, %s",
- __func__, hash.ToString(), FormatStateMessage(state));
+ // If we're using promiscuousmempoolflags, we may hit this normally
+ // Check if current block has some flags that scriptVerifyFlags
+ // does not before printing an ominous warning
+ if (!(~scriptVerifyFlags & currentBlockScriptVerifyFlags)) {
+ return error("%s: BUG! PLEASE REPORT THIS! ConnectInputs failed against latest-block but not STANDARD flags %s, %s",
+ __func__, hash.ToString(), FormatStateMessage(state));
+ } else {
+ if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, false, txdata)) {
+ return error("%s: ConnectInputs failed against MANDATORY but not STANDARD flags due to promiscuous mempool %s, %s",
+ __func__, hash.ToString(), FormatStateMessage(state));
+ } else {
+ LogPrintf("Warning: -promiscuousmempool flags set to not include currently enforced soft forks, this may break mining or otherwise cause instability!\n");
+ }
+ }
}
// Remove conflicting transactions from the mempool
- BOOST_FOREACH(const CTxMemPool::txiter it, allConflicting)
+ for (const CTxMemPool::txiter it : allConflicting)
{
- LogPrint("mempool", "replacing tx %s with %s for %s BTC additional fees, %d delta bytes\n",
+ LogPrint(BCLog::MEMPOOL, "replacing tx %s with %s for %s BTC additional fees, %d delta bytes\n",
it->GetTx().GetHash().ToString(),
hash.ToString(),
FormatMoney(nModifiedFees - nConflictingFees),
(int)nSize - (int)nConflictingSize);
+ if (plTxnReplaced)
+ plTxnReplaced->push_back(it->GetSharedTx());
}
- pool.RemoveStaged(allConflicting, false);
+ pool.RemoveStaged(allConflicting, false, MemPoolRemovalReason::REPLACED);
- // This transaction should only count for fee estimation if
- // the node is not behind and it is not dependent on any other
- // transactions in the mempool
- bool validForFeeEstimation = IsCurrentForFeeEstimation() && pool.HasNoInputsOf(tx);
+ // This transaction should only count for fee estimation if:
+ // - it isn't a BIP 125 replacement transaction (may not be widely supported)
+ // - it's not being readded during a reorg which bypasses typical mempool fee limits
+ // - the node is not behind
+ // - the transaction is not dependent on any other transactions in the mempool
+ bool validForFeeEstimation = !fReplacementTransaction && !bypass_limits && IsCurrentForFeeEstimation() && pool.HasNoInputsOf(tx);
// Store transaction in memory
pool.addUnchecked(hash, entry, setAncestors, validForFeeEstimation);
// trim mempool and check if tx was trimmed
- if (!fOverrideMempoolLimit) {
- LimitMempoolSize(pool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);
+ if (!bypass_limits) {
+ LimitMempoolSize(pool, gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);
if (!pool.exists(hash))
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool full");
}
}
- GetMainSignals().SyncTransaction(tx, NULL, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK);
+ GetMainSignals().TransactionAddedToMempool(ptx);
return true;
}
-bool AcceptToMemoryPoolWithTime(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, bool fLimitFree,
- bool* pfMissingInputs, int64_t nAcceptTime, bool fOverrideMempoolLimit, const CAmount nAbsurdFee)
+/** (try to) add transaction to memory pool with a specified acceptance time **/
+static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx,
+ bool* pfMissingInputs, int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,
+ bool bypass_limits, const CAmount nAbsurdFee)
{
- std::vector<uint256> vHashTxToUncache;
- bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, nAcceptTime, fOverrideMempoolLimit, nAbsurdFee, vHashTxToUncache);
+ std::vector<COutPoint> coins_to_uncache;
+ bool res = AcceptToMemoryPoolWorker(chainparams, pool, state, tx, pfMissingInputs, nAcceptTime, plTxnReplaced, bypass_limits, nAbsurdFee, coins_to_uncache);
if (!res) {
- BOOST_FOREACH(const uint256& hashTx, vHashTxToUncache)
+ for (const COutPoint& hashTx : coins_to_uncache)
pcoinsTip->Uncache(hashTx);
}
// After we've (potentially) uncached entries, ensure our coins cache is still within its size limits
CValidationState stateDummy;
- FlushStateToDisk(stateDummy, FLUSH_STATE_PERIODIC);
+ FlushStateToDisk(chainparams, stateDummy, FLUSH_STATE_PERIODIC);
return res;
}
-bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, bool fLimitFree,
- bool* pfMissingInputs, bool fOverrideMempoolLimit, const CAmount nAbsurdFee)
+bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx,
+ bool* pfMissingInputs, std::list<CTransactionRef>* plTxnReplaced,
+ bool bypass_limits, const CAmount nAbsurdFee)
{
- return AcceptToMemoryPoolWithTime(pool, state, tx, fLimitFree, pfMissingInputs, GetTime(), fOverrideMempoolLimit, nAbsurdFee);
+ const CChainParams& chainparams = Params();
+ return AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, pfMissingInputs, GetTime(), plTxnReplaced, bypass_limits, nAbsurdFee);
}
/** Return transaction in txOut, and if it was found inside a block, its hash is placed in hashBlock */
bool GetTransaction(const uint256 &hash, CTransactionRef &txOut, const Consensus::Params& consensusParams, uint256 &hashBlock, bool fAllowSlow)
{
- CBlockIndex *pindexSlow = NULL;
+ CBlockIndex *pindexSlow = nullptr;
LOCK(cs_main);
@@ -1033,15 +941,8 @@ bool GetTransaction(const uint256 &hash, CTransactionRef &txOut, const Consensus
}
if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it
- int nHeight = -1;
- {
- const CCoinsViewCache& view = *pcoinsTip;
- const CCoins* coins = view.AccessCoins(hash);
- if (coins)
- nHeight = coins->nHeight;
- }
- if (nHeight > 0)
- pindexSlow = chainActive[nHeight];
+ const Coin& coin = AccessByTxid(*pcoinsTip, hash);
+ if (!coin.IsSpent()) pindexSlow = chainActive[coin.nHeight];
}
if (pindexSlow) {
@@ -1070,7 +971,7 @@ bool GetTransaction(const uint256 &hash, CTransactionRef &txOut, const Consensus
// CBlock and CBlockIndex
//
-bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart)
+static bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart)
{
// Open history file to append
CAutoFile fileout(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION);
@@ -1140,8 +1041,6 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
bool IsInitialBlockDownload()
{
- const CChainParams& chainParams = Params();
-
// Once this function has returned false, it must remain false.
static std::atomic<bool> latchToFalse{false};
// Optimization: pre-test latch before taking the lock.
@@ -1153,22 +1052,23 @@ bool IsInitialBlockDownload()
return false;
if (fImporting || fReindex)
return true;
- if (chainActive.Tip() == NULL)
+ if (chainActive.Tip() == nullptr)
return true;
- if (chainActive.Tip()->nChainWork < UintToArith256(chainParams.GetConsensus().nMinimumChainWork))
+ if (chainActive.Tip()->nChainWork < nMinimumChainWork)
return true;
if (chainActive.Tip()->GetBlockTime() < (GetTime() - nMaxTipAge))
return true;
+ LogPrintf("Leaving InitialBlockDownload (latching to false)\n");
latchToFalse.store(true, std::memory_order_relaxed);
return false;
}
-CBlockIndex *pindexBestForkTip = NULL, *pindexBestForkBase = NULL;
+CBlockIndex *pindexBestForkTip = nullptr, *pindexBestForkBase = nullptr;
static void AlertNotify(const std::string& strMessage)
{
uiInterface.NotifyAlertChanged();
- std::string strCmd = GetArg("-alertnotify", "");
+ std::string strCmd = gArgs.GetArg("-alertnotify", "");
if (strCmd.empty()) return;
// Alert text should be plain ascii coming from a trusted source, but to
@@ -1182,7 +1082,7 @@ static void AlertNotify(const std::string& strMessage)
boost::thread t(runCommand, strCmd); // thread runs free
}
-void CheckForkWarningConditions()
+static void CheckForkWarningConditions()
{
AssertLockHeld(cs_main);
// Before we get past initial download, we cannot reliably alert about forks
@@ -1193,7 +1093,7 @@ void CheckForkWarningConditions()
// If our best fork is no longer within 72 blocks (+/- 12 hours if no one mines it)
// of our head, drop it
if (pindexBestForkTip && chainActive.Height() - pindexBestForkTip->nHeight >= 72)
- pindexBestForkTip = NULL;
+ pindexBestForkTip = nullptr;
if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > chainActive.Tip()->nChainWork + (GetBlockProof(*chainActive.Tip()) * 6)))
{
@@ -1223,7 +1123,7 @@ void CheckForkWarningConditions()
}
}
-void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip)
+static void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip)
{
AssertLockHeld(cs_main);
// If we are on a fork that is sufficiently large, set a warning flag
@@ -1245,7 +1145,7 @@ void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip)
// or a chain that is entirely longer than ours and invalid (note that this should be detected by both)
// We define it this way because it allows us to only store the highest fork tip (+ base) which meets
// the 7-block condition and from this always have the most-likely-to-cause-warning fork
- if (pfork && (!pindexBestForkTip || (pindexBestForkTip && pindexNewForkTip->nHeight > pindexBestForkTip->nHeight)) &&
+ if (pfork && (!pindexBestForkTip || pindexNewForkTip->nHeight > pindexBestForkTip->nHeight) &&
pindexNewForkTip->nChainWork - pfork->nChainWork > (GetBlockProof(*pfork) * 7) &&
chainActive.Height() - pindexNewForkTip->nHeight < 72)
{
@@ -1287,25 +1187,14 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txund
// mark inputs spent
if (!tx.IsCoinBase()) {
txundo.vprevout.reserve(tx.vin.size());
- BOOST_FOREACH(const CTxIn &txin, tx.vin) {
- CCoinsModifier coins = inputs.ModifyCoins(txin.prevout.hash);
- unsigned nPos = txin.prevout.n;
-
- if (nPos >= coins->vout.size() || coins->vout[nPos].IsNull())
- assert(false);
- // mark an outpoint spent, and construct undo information
- txundo.vprevout.push_back(CTxInUndo(coins->vout[nPos]));
- coins->Spend(nPos);
- if (coins->vout.size() == 0) {
- CTxInUndo& undo = txundo.vprevout.back();
- undo.nHeight = coins->nHeight;
- undo.fCoinBase = coins->fCoinBase;
- undo.nVersion = coins->nVersion;
- }
+ for (const CTxIn &txin : tx.vin) {
+ txundo.vprevout.emplace_back();
+ bool is_spent = inputs.SpendCoin(txin.prevout, &txundo.vprevout.back());
+ assert(is_spent);
}
}
// add outputs
- inputs.ModifyNewCoins(tx.GetHash(), tx.IsCoinBase())->FromTx(tx, nHeight);
+ AddCoins(inputs, tx, nHeight);
}
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
@@ -1317,10 +1206,7 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
bool CScriptCheck::operator()() {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
const CScriptWitness *witness = &ptxTo->vin[nIn].scriptWitness;
- if (!VerifyScript(scriptSig, scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *txdata), &error)) {
- return false;
- }
- return true;
+ return VerifyScript(scriptSig, m_tx_out.scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, m_tx_out.nValue, cacheStore, *txdata), &error);
}
int GetSpendHeight(const CCoinsViewCache& inputs)
@@ -1330,53 +1216,34 @@ int GetSpendHeight(const CCoinsViewCache& inputs)
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(false, 0, "", "Inputs unavailable");
-
- CAmount nValueIn = 0;
- CAmount nFees = 0;
- for (unsigned int i = 0; i < tx.vin.size(); i++)
- {
- const COutPoint &prevout = tx.vin[i].prevout;
- const CCoins *coins = inputs.AccessCoins(prevout.hash);
- assert(coins);
-
- // If prev is coinbase, check that it's matured
- if (coins->IsCoinBase()) {
- if (nSpendHeight - coins->nHeight < COINBASE_MATURITY)
- 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, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange");
+static CuckooCache::cache<uint256, SignatureCacheHasher> scriptExecutionCache;
+static uint256 scriptExecutionCacheNonce(GetRandHash());
- }
-
- if (nValueIn < tx.GetValueOut())
- 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, false, REJECT_INVALID, "bad-txns-fee-negative");
- nFees += nTxFee;
- if (!MoneyRange(nFees))
- return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-outofrange");
- return true;
+void InitScriptExecutionCache() {
+ // nMaxCacheSize is unsigned. If -maxsigcachesize is set to zero,
+ // setup_bytes creates the minimum possible cache (2 elements).
+ size_t nMaxCacheSize = std::min(std::max((int64_t)0, gArgs.GetArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE) / 2), MAX_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20);
+ size_t nElems = scriptExecutionCache.setup_bytes(nMaxCacheSize);
+ LogPrintf("Using %zu MiB out of %zu/2 requested for script execution cache, able to store %zu elements\n",
+ (nElems*sizeof(uint256)) >>20, (nMaxCacheSize*2)>>20, nElems);
}
-}// namespace Consensus
-bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks)
+/**
+ * Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
+ * This does not modify the UTXO set.
+ *
+ * If pvChecks is not nullptr, script checks are pushed onto it instead of being performed inline. Any
+ * script checks which are not necessary (eg due to script execution cache hits) are, obviously,
+ * not pushed onto pvChecks/run.
+ *
+ * Setting cacheSigStore/cacheFullScriptStore to false will remove elements from the corresponding cache
+ * which are matched. This is useful for checking blocks where we will likely never need the cache
+ * entry again.
+ *
+ * Non-static (and re-declared) in src/test/txvalidationcache_tests.cpp
+ */
+bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks)
{
if (!tx.IsCoinBase())
{
@@ -1391,18 +1258,39 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// Helps prevent CPU exhaustion attacks.
// Skip script verification when connecting blocks under the
- // assumedvalid block. Assuming the assumedvalid block is valid this
+ // assumevalid block. Assuming the assumevalid block is valid this
// is safe because block merkle hashes are still computed and checked,
// Of course, if an assumed valid block is invalid due to false scriptSigs
// this optimization would allow an invalid chain to be accepted.
if (fScriptChecks) {
+ // First check if script executions have been cached with the same
+ // flags. Note that this assumes that the inputs provided are
+ // correct (ie that the transaction hash which is in tx's prevouts
+ // properly commits to the scriptPubKey in the inputs view of that
+ // transaction).
+ uint256 hashCacheEntry;
+ // We only use the first 19 bytes of nonce to avoid a second SHA
+ // round - giving us 19 + 32 + 4 = 55 bytes (+ 8 + 1 = 64)
+ static_assert(55 - sizeof(flags) - 32 >= 128/8, "Want at least 128 bits of nonce for script execution cache");
+ CSHA256().Write(scriptExecutionCacheNonce.begin(), 55 - sizeof(flags) - 32).Write(tx.GetWitnessHash().begin(), 32).Write((unsigned char*)&flags, sizeof(flags)).Finalize(hashCacheEntry.begin());
+ AssertLockHeld(cs_main); //TODO: Remove this requirement by making CuckooCache not require external locks
+ if (scriptExecutionCache.contains(hashCacheEntry, !cacheFullScriptStore)) {
+ return true;
+ }
+
for (unsigned int i = 0; i < tx.vin.size(); i++) {
const COutPoint &prevout = tx.vin[i].prevout;
- const CCoins* coins = inputs.AccessCoins(prevout.hash);
- assert(coins);
+ const Coin& coin = inputs.AccessCoin(prevout);
+ assert(!coin.IsSpent());
+
+ // We very carefully only pass in things to CScriptCheck which
+ // are clearly committed to by tx' witness hash. This provides
+ // a sanity check that our caching is not introducing consensus
+ // failures through additional data in, eg, the coins being
+ // spent being checked as a part of CScriptCheck.
// Verify signature
- CScriptCheck check(*coins, tx, i, flags, cacheStore, &txdata);
+ CScriptCheck check(coin.out, tx, i, flags, cacheSigStore, &txdata);
if (pvChecks) {
pvChecks->push_back(CScriptCheck());
check.swap(pvChecks->back());
@@ -1414,13 +1302,13 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// arguments; if so, don't trigger DoS protection to
// avoid splitting the network between upgraded and
// non-upgraded nodes.
- CScriptCheck check2(*coins, tx, i,
- flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, &txdata);
+ CScriptCheck check2(coin.out, tx, i,
+ flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheSigStore, &txdata);
if (check2())
return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
}
// Failures of other flags indicate a transaction that is
- // invalid in new blocks, e.g. a invalid P2SH. We DoS ban
+ // invalid in new blocks, e.g. an invalid P2SH. We DoS ban
// such nodes as they are not following the protocol. That
// said during an upgrade careful thought should be taken
// as to the correct behavior - we may want to continue
@@ -1429,6 +1317,12 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
return state.DoS(100,false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError())));
}
}
+
+ if (cacheFullScriptStore && !pvChecks) {
+ // We executed all of the provided scripts, and were told to
+ // cache the result. Do so now.
+ scriptExecutionCache.insert(hashCacheEntry);
+ }
}
}
@@ -1473,8 +1367,10 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uin
// Read block
uint256 hashChecksum;
+ CHashVerifier<CAutoFile> verifier(&filein); // We need a CHashVerifier as reserializing may lose data
try {
- filein >> blockundo;
+ verifier << hashBlock;
+ verifier >> blockundo;
filein >> hashChecksum;
}
catch (const std::exception& e) {
@@ -1482,10 +1378,7 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uin
}
// Verify checksum
- CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
- hasher << hashBlock;
- hasher << blockundo;
- if (hashChecksum != hasher.GetHash())
+ if (hashChecksum != verifier.GetHash())
return error("%s: Checksum mismatch", __func__);
return true;
@@ -1509,107 +1402,111 @@ bool AbortNode(CValidationState& state, const std::string& strMessage, const std
return state.Error(strMessage);
}
-} // anon namespace
+} // namespace
+
+enum DisconnectResult
+{
+ DISCONNECT_OK, // All good.
+ DISCONNECT_UNCLEAN, // Rolled back, but UTXO set was inconsistent with block.
+ DISCONNECT_FAILED // Something else went wrong.
+};
/**
- * Apply the undo operation of a CTxInUndo to the given chain state.
- * @param undo The undo object.
+ * Restore the UTXO in a Coin at a given COutPoint
+ * @param undo The Coin to be restored.
* @param view The coins view to which to apply the changes.
* @param out The out point that corresponds to the tx input.
- * @return True on success.
+ * @return A DisconnectResult as an int
*/
-bool ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, const COutPoint& out)
+int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out)
{
bool fClean = true;
- CCoinsModifier coins = view.ModifyCoins(out.hash);
- if (undo.nHeight != 0) {
- // undo data contains height: this is the last output of the prevout tx being spent
- if (!coins->IsPruned())
- fClean = fClean && error("%s: undo data overwriting existing transaction", __func__);
- coins->Clear();
- coins->fCoinBase = undo.fCoinBase;
- coins->nHeight = undo.nHeight;
- coins->nVersion = undo.nVersion;
- } else {
- if (coins->IsPruned())
- fClean = fClean && error("%s: undo data adding output to missing transaction", __func__);
+ if (view.HaveCoin(out)) fClean = false; // overwriting transaction output
+
+ if (undo.nHeight == 0) {
+ // Missing undo metadata (height and coinbase). Older versions included this
+ // information only in undo records for the last spend of a transactions'
+ // outputs. This implies that it must be present for some other output of the same tx.
+ const Coin& alternate = AccessByTxid(view, out.hash);
+ if (!alternate.IsSpent()) {
+ undo.nHeight = alternate.nHeight;
+ undo.fCoinBase = alternate.fCoinBase;
+ } else {
+ return DISCONNECT_FAILED; // adding output for transaction without known metadata
+ }
}
- if (coins->IsAvailable(out.n))
- fClean = fClean && error("%s: undo data overwriting existing output", __func__);
- if (coins->vout.size() < out.n+1)
- coins->vout.resize(out.n+1);
- coins->vout[out.n] = undo.txout;
+ // The potential_overwrite parameter to AddCoin is only allowed to be false if we know for
+ // sure that the coin did not already exist in the cache. As we have queried for that above
+ // using HaveCoin, we don't need to guess. When fClean is false, a coin already existed and
+ // it is an overwrite.
+ view.AddCoin(out, std::move(undo), !fClean);
- return fClean;
+ return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN;
}
-bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean)
+/** Undo the effects of this block (with given index) on the UTXO set represented by coins.
+ * When FAILED is returned, view is left in an indeterminate state. */
+static DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view)
{
- assert(pindex->GetBlockHash() == view.GetBestBlock());
-
- if (pfClean)
- *pfClean = false;
-
bool fClean = true;
CBlockUndo blockUndo;
CDiskBlockPos pos = pindex->GetUndoPos();
- if (pos.IsNull())
- return error("DisconnectBlock(): no undo data available");
- if (!UndoReadFromDisk(blockUndo, pos, pindex->pprev->GetBlockHash()))
- return error("DisconnectBlock(): failure reading undo data");
+ if (pos.IsNull()) {
+ error("DisconnectBlock(): no undo data available");
+ return DISCONNECT_FAILED;
+ }
+ if (!UndoReadFromDisk(blockUndo, pos, pindex->pprev->GetBlockHash())) {
+ error("DisconnectBlock(): failure reading undo data");
+ return DISCONNECT_FAILED;
+ }
- if (blockUndo.vtxundo.size() + 1 != block.vtx.size())
- return error("DisconnectBlock(): block and undo data inconsistent");
+ if (blockUndo.vtxundo.size() + 1 != block.vtx.size()) {
+ error("DisconnectBlock(): block and undo data inconsistent");
+ return DISCONNECT_FAILED;
+ }
// undo transactions in reverse order
for (int i = block.vtx.size() - 1; i >= 0; i--) {
const CTransaction &tx = *(block.vtx[i]);
uint256 hash = tx.GetHash();
+ bool is_coinbase = tx.IsCoinBase();
// Check that all outputs are available and match the outputs in the block itself
// exactly.
- {
- CCoinsModifier outs = view.ModifyCoins(hash);
- outs->ClearUnspendable();
-
- CCoins outsBlock(tx, pindex->nHeight);
- // The CCoins serialization does not serialize negative numbers.
- // No network rules currently depend on the version here, so an inconsistency is harmless
- // but it must be corrected before txout nversion ever influences a network rule.
- if (outsBlock.nVersion < 0)
- outs->nVersion = outsBlock.nVersion;
- if (*outs != outsBlock)
- fClean = fClean && error("DisconnectBlock(): added transaction mismatch? database corrupted");
-
- // remove outputs
- outs->Clear();
+ for (size_t o = 0; o < tx.vout.size(); o++) {
+ if (!tx.vout[o].scriptPubKey.IsUnspendable()) {
+ COutPoint out(hash, o);
+ Coin coin;
+ bool is_spent = view.SpendCoin(out, &coin);
+ if (!is_spent || tx.vout[o] != coin.out || pindex->nHeight != coin.nHeight || is_coinbase != coin.fCoinBase) {
+ fClean = false; // transaction output mismatch
+ }
+ }
}
// restore inputs
if (i > 0) { // not coinbases
- const CTxUndo &txundo = blockUndo.vtxundo[i-1];
- if (txundo.vprevout.size() != tx.vin.size())
- return error("DisconnectBlock(): transaction and undo data inconsistent");
+ CTxUndo &txundo = blockUndo.vtxundo[i-1];
+ if (txundo.vprevout.size() != tx.vin.size()) {
+ error("DisconnectBlock(): transaction and undo data inconsistent");
+ return DISCONNECT_FAILED;
+ }
for (unsigned int j = tx.vin.size(); j-- > 0;) {
const COutPoint &out = tx.vin[j].prevout;
- const CTxInUndo &undo = txundo.vprevout[j];
- if (!ApplyTxInUndo(undo, view, out))
- fClean = false;
+ int res = ApplyTxInUndo(std::move(txundo.vprevout[j]), view, out);
+ if (res == DISCONNECT_FAILED) return DISCONNECT_FAILED;
+ fClean = fClean && res != DISCONNECT_UNCLEAN;
}
+ // At this point, all of txundo.vprevout should have been moved out.
}
}
// move best block pointer to prevout block
view.SetBestBlock(pindex->pprev->GetBlockHash());
- if (pfClean) {
- *pfClean = fClean;
- return true;
- }
-
- return fClean;
+ return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN;
}
void static FlushBlockFile(bool fFinalize = false)
@@ -1635,7 +1532,7 @@ void static FlushBlockFile(bool fFinalize = false)
}
}
-bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize);
+static bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize);
static CCheckQueue<CScriptCheck> scriptcheckqueue(128);
@@ -1671,14 +1568,14 @@ private:
int bit;
public:
- WarningBitsConditionChecker(int bitIn) : bit(bitIn) {}
+ explicit WarningBitsConditionChecker(int bitIn) : bit(bitIn) {}
- int64_t BeginTime(const Consensus::Params& params) const { return 0; }
- int64_t EndTime(const Consensus::Params& params) const { return std::numeric_limits<int64_t>::max(); }
- int Period(const Consensus::Params& params) const { return params.nMinerConfirmationWindow; }
- int Threshold(const Consensus::Params& params) const { return params.nRuleChangeActivationThreshold; }
+ int64_t BeginTime(const Consensus::Params& params) const override { return 0; }
+ int64_t EndTime(const Consensus::Params& params) const override { return std::numeric_limits<int64_t>::max(); }
+ int Period(const Consensus::Params& params) const override { return params.nMinerConfirmationWindow; }
+ int Threshold(const Consensus::Params& params) const override { return params.nRuleChangeActivationThreshold; }
- bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const
+ bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const override
{
return ((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) &&
((pindex->nVersion >> bit) & 1) != 0 &&
@@ -1689,6 +1586,41 @@ public:
// Protected by cs_main
static ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS];
+static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consensus::Params& consensusparams) {
+ AssertLockHeld(cs_main);
+
+ // BIP16 didn't become active until Apr 1 2012
+ int64_t nBIP16SwitchTime = 1333238400;
+ bool fStrictPayToScriptHash = (pindex->GetBlockTime() >= nBIP16SwitchTime);
+
+ unsigned int flags = fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE;
+
+ // Start enforcing the DERSIG (BIP66) rule
+ if (pindex->nHeight >= consensusparams.BIP66Height) {
+ flags |= SCRIPT_VERIFY_DERSIG;
+ }
+
+ // Start enforcing CHECKLOCKTIMEVERIFY (BIP65) rule
+ if (pindex->nHeight >= consensusparams.BIP65Height) {
+ flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
+ }
+
+ // Start enforcing BIP68 (sequence locks) and BIP112 (CHECKSEQUENCEVERIFY) using versionbits logic.
+ if (VersionBitsState(pindex->pprev, consensusparams, Consensus::DEPLOYMENT_CSV, versionbitscache) == THRESHOLD_ACTIVE) {
+ flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY;
+ }
+
+ // Start enforcing WITNESS rules using versionbits logic.
+ if (IsWitnessEnabled(pindex->pprev, consensusparams)) {
+ flags |= SCRIPT_VERIFY_WITNESS;
+ flags |= SCRIPT_VERIFY_NULLDUMMY;
+ }
+
+ return flags;
+}
+
+
+
static int64_t nTimeCheck = 0;
static int64_t nTimeForks = 0;
static int64_t nTimeVerify = 0;
@@ -1696,12 +1628,19 @@ static int64_t nTimeConnect = 0;
static int64_t nTimeIndex = 0;
static int64_t nTimeCallbacks = 0;
static int64_t nTimeTotal = 0;
+static int64_t nBlocksTotal = 0;
-bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex,
- CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck)
+/** Apply the effects of this block (with given index) on the UTXO set represented by coins.
+ * Validity checks that depend on the UTXO set are also done; ConnectBlock()
+ * can fail if those validity checks fail (among other reasons). */
+static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex,
+ CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false)
{
AssertLockHeld(cs_main);
-
+ assert(pindex);
+ // pindex->phashBlock can be null if called by CreateNewBlock/TestBlockValidity
+ assert((pindex->phashBlock == nullptr) ||
+ (*pindex->phashBlock == block.GetHash()));
int64_t nTimeStart = GetTimeMicros();
// Check it again in case a previous version let a bad block in
@@ -1709,7 +1648,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
return error("%s: Consensus::CheckBlock: %s", __func__, FormatStateMessage(state));
// verify that the view's current state corresponds to the previous block
- uint256 hashPrevBlock = pindex->pprev == NULL ? uint256() : pindex->pprev->GetBlockHash();
+ uint256 hashPrevBlock = pindex->pprev == nullptr ? uint256() : pindex->pprev->GetBlockHash();
assert(hashPrevBlock == view.GetBestBlock());
// Special case for the genesis block, skipping connection of its transactions
@@ -1720,6 +1659,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
return true;
}
+ nBlocksTotal++;
+
bool fScriptChecks = true;
if (!hashAssumeValid.IsNull()) {
// We've been configured with the hash of a block which has been externally verified to have a valid history.
@@ -1731,9 +1672,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
if (it != mapBlockIndex.end()) {
if (it->second->GetAncestor(pindex->nHeight) == pindex &&
pindexBestHeader->GetAncestor(pindex->nHeight) == pindex &&
- pindexBestHeader->nChainWork >= UintToArith256(chainparams.GetConsensus().nMinimumChainWork)) {
+ pindexBestHeader->nChainWork >= nMinimumChainWork) {
// This block is a member of the assumed verified chain and an ancestor of the best header.
- // The equivalent time check discourages hashpower from extorting the network via DOS attack
+ // The equivalent time check discourages hash power from extorting the network via DOS attack
// into accepting an invalid block through telling users they must manually set assumevalid.
// Requiring a software change or burying the invalid block, regardless of the setting, makes
// it hard to hide the implication of the demand. This also avoids having release candidates
@@ -1747,7 +1688,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
}
int64_t nTime1 = GetTimeMicros(); nTimeCheck += nTime1 - nTimeStart;
- LogPrint("bench", " - Sanity checks: %.2fms [%.2fs]\n", 0.001 * (nTime1 - nTimeStart), nTimeCheck * 0.000001);
+ LogPrint(BCLog::BENCH, " - Sanity checks: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime1 - nTimeStart), nTimeCheck * MICRO, nTimeCheck * MILLI / nBlocksTotal);
// Do not allow blocks that contain transactions which 'overwrite' older transactions,
// unless those are already completely spent.
@@ -1771,54 +1712,37 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
// before the first had been spent. Since those coinbases are sufficiently buried its no longer possible to create further
// duplicate transactions descending from the known pairs either.
// If we're on the known chain at height greater than where BIP34 activated, we can save the db accesses needed for the BIP30 check.
+ assert(pindex->pprev);
CBlockIndex *pindexBIP34height = pindex->pprev->GetAncestor(chainparams.GetConsensus().BIP34Height);
//Only continue to enforce if we're below BIP34 activation height or the block hash at that height doesn't correspond.
fEnforceBIP30 = fEnforceBIP30 && (!pindexBIP34height || !(pindexBIP34height->GetBlockHash() == chainparams.GetConsensus().BIP34Hash));
if (fEnforceBIP30) {
for (const auto& tx : block.vtx) {
- const CCoins* coins = view.AccessCoins(tx->GetHash());
- if (coins && !coins->IsPruned())
- return state.DoS(100, error("ConnectBlock(): tried to overwrite transaction"),
- REJECT_INVALID, "bad-txns-BIP30");
+ for (size_t o = 0; o < tx->vout.size(); o++) {
+ if (view.HaveCoin(COutPoint(tx->GetHash(), o))) {
+ return state.DoS(100, error("ConnectBlock(): tried to overwrite transaction"),
+ REJECT_INVALID, "bad-txns-BIP30");
+ }
+ }
}
}
- // BIP16 didn't become active until Apr 1 2012
- int64_t nBIP16SwitchTime = 1333238400;
- bool fStrictPayToScriptHash = (pindex->GetBlockTime() >= nBIP16SwitchTime);
-
- unsigned int flags = fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE;
-
- // Start enforcing the DERSIG (BIP66) rule
- if (pindex->nHeight >= chainparams.GetConsensus().BIP66Height) {
- flags |= SCRIPT_VERIFY_DERSIG;
- }
-
- // Start enforcing CHECKLOCKTIMEVERIFY (BIP65) rule
- if (pindex->nHeight >= chainparams.GetConsensus().BIP65Height) {
- flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
- }
-
// Start enforcing BIP68 (sequence locks) and BIP112 (CHECKSEQUENCEVERIFY) using versionbits logic.
int nLockTimeFlags = 0;
if (VersionBitsState(pindex->pprev, chainparams.GetConsensus(), Consensus::DEPLOYMENT_CSV, versionbitscache) == THRESHOLD_ACTIVE) {
- flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY;
nLockTimeFlags |= LOCKTIME_VERIFY_SEQUENCE;
}
- // Start enforcing WITNESS rules using versionbits logic.
- if (IsWitnessEnabled(pindex->pprev, chainparams.GetConsensus())) {
- flags |= SCRIPT_VERIFY_WITNESS;
- flags |= SCRIPT_VERIFY_NULLDUMMY;
- }
+ // Get the script flags for this block
+ unsigned int flags = GetBlockScriptFlags(pindex, chainparams.GetConsensus());
int64_t nTime2 = GetTimeMicros(); nTimeForks += nTime2 - nTime1;
- LogPrint("bench", " - Fork checks: %.2fms [%.2fs]\n", 0.001 * (nTime2 - nTime1), nTimeForks * 0.000001);
+ LogPrint(BCLog::BENCH, " - Fork checks: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime2 - nTime1), nTimeForks * MICRO, nTimeForks * MILLI / nBlocksTotal);
CBlockUndo blockundo;
- CCheckQueueControl<CScriptCheck> control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL);
+ CCheckQueueControl<CScriptCheck> control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : nullptr);
std::vector<int> prevheights;
CAmount nFees = 0;
@@ -1847,7 +1771,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
// be in ConnectBlock because they require the UTXO set
prevheights.resize(tx.vin.size());
for (size_t j = 0; j < tx.vin.size(); j++) {
- prevheights[j] = view.AccessCoins(tx.vin[j].prevout.hash)->nHeight;
+ prevheights[j] = view.AccessCoin(tx.vin[j].prevout).nHeight;
}
if (!SequenceLocks(tx, nLockTimeFlags, &prevheights, *pindex)) {
@@ -1872,7 +1796,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
std::vector<CScriptCheck> vChecks;
bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */
- if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, txdata[i], nScriptCheckThreads ? &vChecks : NULL))
+ if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, fCacheResults, txdata[i], nScriptCheckThreads ? &vChecks : nullptr))
return error("ConnectBlock(): CheckInputs on %s failed with %s",
tx.GetHash().ToString(), FormatStateMessage(state));
control.Add(vChecks);
@@ -1888,7 +1812,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
}
int64_t nTime3 = GetTimeMicros(); nTimeConnect += nTime3 - nTime2;
- LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime3 - nTime2), 0.001 * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * 0.000001);
+ LogPrint(BCLog::BENCH, " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs (%.2fms/blk)]\n", (unsigned)block.vtx.size(), MILLI * (nTime3 - nTime2), MILLI * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : MILLI * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * MICRO, nTimeConnect * MILLI / nBlocksTotal);
CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus());
if (block.vtx[0]->GetValueOut() > blockReward)
@@ -1898,9 +1822,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
REJECT_INVALID, "bad-cb-amount");
if (!control.Wait())
- return state.DoS(100, false);
+ return state.DoS(100, error("%s: CheckQueue failed", __func__), REJECT_INVALID, "block-validation-failed");
int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2;
- LogPrint("bench", " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs]\n", nInputs - 1, 0.001 * (nTime4 - nTime2), nInputs <= 1 ? 0 : 0.001 * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * 0.000001);
+ LogPrint(BCLog::BENCH, " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs (%.2fms/blk)]\n", nInputs - 1, MILLI * (nTime4 - nTime2), nInputs <= 1 ? 0 : MILLI * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * MICRO, nTimeVerify * MILLI / nBlocksTotal);
if (fJustCheck)
return true;
@@ -1928,20 +1852,15 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
if (!pblocktree->WriteTxIndex(vPos))
return AbortNode(state, "Failed to write transaction index");
+ assert(pindex->phashBlock);
// add this block to the view's block chain
view.SetBestBlock(pindex->GetBlockHash());
int64_t nTime5 = GetTimeMicros(); nTimeIndex += nTime5 - nTime4;
- LogPrint("bench", " - Index writing: %.2fms [%.2fs]\n", 0.001 * (nTime5 - nTime4), nTimeIndex * 0.000001);
-
- // Watch for changes to the previous coinbase transaction.
- static uint256 hashPrevBestCoinBase;
- GetMainSignals().UpdatedTransaction(hashPrevBestCoinBase);
- hashPrevBestCoinBase = block.vtx[0]->GetHash();
-
+ LogPrint(BCLog::BENCH, " - Index writing: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime5 - nTime4), nTimeIndex * MICRO, nTimeIndex * MILLI / nBlocksTotal);
int64_t nTime6 = GetTimeMicros(); nTimeCallbacks += nTime6 - nTime5;
- LogPrint("bench", " - Callbacks: %.2fms [%.2fs]\n", 0.001 * (nTime6 - nTime5), nTimeCallbacks * 0.000001);
+ LogPrint(BCLog::BENCH, " - Callbacks: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime6 - nTime5), nTimeCallbacks * MICRO, nTimeCallbacks * MILLI / nBlocksTotal);
return true;
}
@@ -1952,98 +1871,102 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
* if they're too large, if it's been a while since the last write,
* or always and in all cases if we're in prune mode and are deleting files.
*/
-bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode, int nManualPruneHeight) {
+bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &state, FlushStateMode mode, int nManualPruneHeight) {
int64_t nMempoolUsage = mempool.DynamicMemoryUsage();
- const CChainParams& chainparams = Params();
- LOCK2(cs_main, cs_LastBlockFile);
+ LOCK(cs_main);
static int64_t nLastWrite = 0;
static int64_t nLastFlush = 0;
static int64_t nLastSetChain = 0;
std::set<int> setFilesToPrune;
bool fFlushForPrune = false;
+ bool fDoFullFlush = false;
+ int64_t nNow = 0;
try {
- if (fPruneMode && (fCheckForPruning || nManualPruneHeight > 0) && !fReindex) {
- if (nManualPruneHeight > 0) {
- FindFilesToPruneManual(setFilesToPrune, nManualPruneHeight);
- } else {
- FindFilesToPrune(setFilesToPrune, chainparams.PruneAfterHeight());
- fCheckForPruning = false;
- }
- if (!setFilesToPrune.empty()) {
- fFlushForPrune = true;
- if (!fHavePruned) {
- pblocktree->WriteFlag("prunedblockfiles", true);
- fHavePruned = true;
- }
- }
- }
- 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;
- }
- int64_t nMempoolSizeMax = GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
- int64_t cacheSize = pcoinsTip->DynamicMemoryUsage();
- int64_t nTotalSpace = nCoinCacheUsage + std::max<int64_t>(nMempoolSizeMax - nMempoolUsage, 0);
- // The cache is large and we're within 10% and 100 MiB of the limit, but we have time now (not in the middle of a block processing).
- bool fCacheLarge = mode == FLUSH_STATE_PERIODIC && cacheSize > std::max((9 * nTotalSpace) / 10, nTotalSpace - 100 * 1024 * 1024);
- // The cache is over the limit, we have to write now.
- bool fCacheCritical = mode == FLUSH_STATE_IF_NEEDED && cacheSize > nTotalSpace;
- // 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();
- // Then update all block file information (which may refer to block and undo files).
- {
- std::vector<std::pair<int, const CBlockFileInfo*> > vFiles;
- vFiles.reserve(setDirtyFileInfo.size());
- for (set<int>::iterator it = setDirtyFileInfo.begin(); it != setDirtyFileInfo.end(); ) {
- vFiles.push_back(make_pair(*it, &vinfoBlockFile[*it]));
- setDirtyFileInfo.erase(it++);
+ {
+ LOCK(cs_LastBlockFile);
+ if (fPruneMode && (fCheckForPruning || nManualPruneHeight > 0) && !fReindex) {
+ if (nManualPruneHeight > 0) {
+ FindFilesToPruneManual(setFilesToPrune, nManualPruneHeight);
+ } else {
+ FindFilesToPrune(setFilesToPrune, chainparams.PruneAfterHeight());
+ fCheckForPruning = false;
}
- std::vector<const CBlockIndex*> vBlocks;
- vBlocks.reserve(setDirtyBlockIndex.size());
- for (set<CBlockIndex*>::iterator it = setDirtyBlockIndex.begin(); it != setDirtyBlockIndex.end(); ) {
- vBlocks.push_back(*it);
- setDirtyBlockIndex.erase(it++);
+ if (!setFilesToPrune.empty()) {
+ fFlushForPrune = true;
+ if (!fHavePruned) {
+ pblocktree->WriteFlag("prunedblockfiles", true);
+ fHavePruned = true;
+ }
}
- if (!pblocktree->WriteBatchSync(vFiles, nLastBlockFile, vBlocks)) {
- return AbortNode(state, "Files to write to block index database");
+ }
+ nNow = GetTimeMicros();
+ // Avoid writing/flushing immediately after startup.
+ if (nLastWrite == 0) {
+ nLastWrite = nNow;
+ }
+ if (nLastFlush == 0) {
+ nLastFlush = nNow;
+ }
+ if (nLastSetChain == 0) {
+ nLastSetChain = nNow;
+ }
+ int64_t nMempoolSizeMax = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
+ int64_t cacheSize = pcoinsTip->DynamicMemoryUsage();
+ int64_t nTotalSpace = nCoinCacheUsage + std::max<int64_t>(nMempoolSizeMax - nMempoolUsage, 0);
+ // The cache is large and we're within 10% and 10 MiB of the limit, but we have time now (not in the middle of a block processing).
+ bool fCacheLarge = mode == FLUSH_STATE_PERIODIC && cacheSize > std::max((9 * nTotalSpace) / 10, nTotalSpace - MAX_BLOCK_COINSDB_USAGE * 1024 * 1024);
+ // The cache is over the limit, we have to write now.
+ bool fCacheCritical = mode == FLUSH_STATE_IF_NEEDED && cacheSize > nTotalSpace;
+ // 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.
+ 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();
+ // Then update all block file information (which may refer to block and undo files).
+ {
+ std::vector<std::pair<int, const CBlockFileInfo*> > vFiles;
+ vFiles.reserve(setDirtyFileInfo.size());
+ for (std::set<int>::iterator it = setDirtyFileInfo.begin(); it != setDirtyFileInfo.end(); ) {
+ vFiles.push_back(std::make_pair(*it, &vinfoBlockFile[*it]));
+ setDirtyFileInfo.erase(it++);
+ }
+ std::vector<const CBlockIndex*> vBlocks;
+ vBlocks.reserve(setDirtyBlockIndex.size());
+ for (std::set<CBlockIndex*>::iterator it = setDirtyBlockIndex.begin(); it != setDirtyBlockIndex.end(); ) {
+ vBlocks.push_back(*it);
+ setDirtyBlockIndex.erase(it++);
+ }
+ if (!pblocktree->WriteBatchSync(vFiles, nLastBlockFile, vBlocks)) {
+ return AbortNode(state, "Failed to write to block index database");
+ }
}
+ // Finally remove any pruned files
+ if (fFlushForPrune)
+ UnlinkPrunedFiles(setFilesToPrune);
+ nLastWrite = nNow;
+ }
+ // Flush best chain related state. This can only be done if the blocks / block index write was also done.
+ if (fDoFullFlush) {
+ // Typical Coin structures on disk are around 48 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(48 * 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;
}
- // Finally remove any pruned files
- if (fFlushForPrune)
- UnlinkPrunedFiles(setFilesToPrune);
- 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 (fDoFullFlush || ((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).
@@ -2058,13 +1981,25 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode, int n
void FlushStateToDisk() {
CValidationState state;
- FlushStateToDisk(state, FLUSH_STATE_ALWAYS);
+ const CChainParams& chainparams = Params();
+ FlushStateToDisk(chainparams, state, FLUSH_STATE_ALWAYS);
}
void PruneAndFlush() {
CValidationState state;
fCheckForPruning = true;
- FlushStateToDisk(state, FLUSH_STATE_NONE);
+ const CChainParams& chainparams = Params();
+ FlushStateToDisk(chainparams, state, FLUSH_STATE_NONE);
+}
+
+static void DoWarning(const std::string& strWarning)
+{
+ static bool fWarned = false;
+ SetMiscWarning(strWarning);
+ if (!fWarned) {
+ AlertNotify(strWarning);
+ fWarned = true;
+ }
}
/** Update chainActive and related internal data structures. */
@@ -2076,7 +2011,6 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
cvBlockChange.notify_all();
- static bool fWarned = false;
std::vector<std::string> warningMessages;
if (!IsInitialBlockDownload())
{
@@ -2086,20 +2020,16 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
WarningBitsConditionChecker checker(bit);
ThresholdState state = checker.GetStateFor(pindex, chainParams.GetConsensus(), warningcache[bit]);
if (state == THRESHOLD_ACTIVE || state == THRESHOLD_LOCKED_IN) {
+ const std::string strWarning = strprintf(_("Warning: unknown new rules activated (versionbit %i)"), bit);
if (state == THRESHOLD_ACTIVE) {
- std::string strWarning = strprintf(_("Warning: unknown new rules activated (versionbit %i)"), bit);
- SetMiscWarning(strWarning);
- if (!fWarned) {
- AlertNotify(strWarning);
- fWarned = true;
- }
+ DoWarning(strWarning);
} else {
- warningMessages.push_back(strprintf("unknown new rules are about to activate (versionbit %i)", bit));
+ warningMessages.push_back(strWarning);
}
}
}
// Check the version of the last 100 blocks to see if we need to upgrade:
- for (int i = 0; i < 100 && pindex != NULL; i++)
+ for (int i = 0; i < 100 && pindex != nullptr; i++)
{
int32_t nExpectedVersion = ComputeBlockVersion(pindex->pprev, chainParams.GetConsensus());
if (pindex->nVersion > VERSIONBITS_LAST_OLD_BLOCK_VERSION && (pindex->nVersion & ~nExpectedVersion) != 0)
@@ -2107,19 +2037,15 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
pindex = pindex->pprev;
}
if (nUpgraded > 0)
- warningMessages.push_back(strprintf("%d of last 100 blocks have unexpected version", nUpgraded));
+ warningMessages.push_back(strprintf(_("%d of last 100 blocks have unexpected version"), nUpgraded));
if (nUpgraded > 100/2)
{
std::string strWarning = _("Warning: Unknown block versions being mined! It's possible unknown rules are in effect");
// notify GetWarnings(), called by Qt and the JSON-RPC code to warn the user:
- SetMiscWarning(strWarning);
- if (!fWarned) {
- AlertNotify(strWarning);
- fWarned = true;
- }
+ DoWarning(strWarning);
}
}
- LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu date='%s' progress=%f cache=%.1fMiB(%utx)", __func__,
+ LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu date='%s' progress=%f cache=%.1fMiB(%utxo)", __func__,
chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), chainActive.Tip()->nVersion,
log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx,
DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()),
@@ -2130,57 +2056,58 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
}
-/** Disconnect chainActive's tip. You probably want to call mempool.removeForReorg and manually re-limit mempool size after this, with cs_main held. */
-bool static DisconnectTip(CValidationState& state, const CChainParams& chainparams, bool fBare = false)
+/** Disconnect chainActive's tip.
+ * After calling, the mempool will be in an inconsistent state, with
+ * transactions from disconnected blocks being added to disconnectpool. You
+ * should make the mempool consistent again by calling UpdateMempoolForReorg.
+ * with cs_main held.
+ *
+ * If disconnectpool is nullptr, then no disconnected transactions are added to
+ * disconnectpool (note that the caller is responsible for mempool consistency
+ * in any case).
+ */
+bool static DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions *disconnectpool)
{
CBlockIndex *pindexDelete = chainActive.Tip();
assert(pindexDelete);
// Read block from disk.
- CBlock block;
+ std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
+ CBlock& block = *pblock;
if (!ReadBlockFromDisk(block, pindexDelete, chainparams.GetConsensus()))
return AbortNode(state, "Failed to read block");
// Apply the block atomically to the chain state.
int64_t nStart = GetTimeMicros();
{
CCoinsViewCache view(pcoinsTip);
- if (!DisconnectBlock(block, state, pindexDelete, view))
+ assert(view.GetBestBlock() == pindexDelete->GetBlockHash());
+ if (DisconnectBlock(block, pindexDelete, view) != DISCONNECT_OK)
return error("DisconnectTip(): DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString());
bool flushed = view.Flush();
assert(flushed);
}
- LogPrint("bench", "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * 0.001);
+ LogPrint(BCLog::BENCH, "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * MILLI);
// Write the chain state to disk, if necessary.
- if (!FlushStateToDisk(state, FLUSH_STATE_IF_NEEDED))
+ if (!FlushStateToDisk(chainparams, state, FLUSH_STATE_IF_NEEDED))
return false;
- if (!fBare) {
- // Resurrect mempool transactions from the disconnected block.
- std::vector<uint256> vHashUpdate;
- for (const auto& it : block.vtx) {
- const CTransaction& tx = *it;
- // ignore validation errors in resurrected transactions
- CValidationState stateDummy;
- if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, it, false, NULL, true)) {
- mempool.removeRecursive(tx);
- } else if (mempool.exists(tx.GetHash())) {
- vHashUpdate.push_back(tx.GetHash());
- }
+ if (disconnectpool) {
+ // Save transactions to re-add to mempool at end of reorg
+ for (auto it = block.vtx.rbegin(); it != block.vtx.rend(); ++it) {
+ disconnectpool->addTransaction(*it);
+ }
+ while (disconnectpool->DynamicMemoryUsage() > MAX_DISCONNECTED_TX_POOL_SIZE * 1000) {
+ // Drop the earliest entry, and remove its children from the mempool.
+ auto it = disconnectpool->queuedTx.get<insertion_order>().begin();
+ mempool.removeRecursive(**it, MemPoolRemovalReason::REORG);
+ disconnectpool->removeEntry(it);
}
- // 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);
}
// Update chainActive and related variables.
UpdateTip(pindexDelete->pprev, chainparams);
// Let wallets know transactions went from 1-confirmed to
// 0-confirmed or conflicted:
- for (const auto& tx : block.vtx) {
- GetMainSignals().SyncTransaction(*tx, pindexDelete->pprev, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK);
- }
+ GetMainSignals().BlockDisconnected(pblock);
return true;
}
@@ -2190,40 +2117,96 @@ static int64_t nTimeFlush = 0;
static int64_t nTimeChainState = 0;
static int64_t nTimePostConnect = 0;
+struct PerBlockConnectTrace {
+ CBlockIndex* pindex = nullptr;
+ std::shared_ptr<const CBlock> pblock;
+ std::shared_ptr<std::vector<CTransactionRef>> conflictedTxs;
+ PerBlockConnectTrace() : conflictedTxs(std::make_shared<std::vector<CTransactionRef>>()) {}
+};
/**
* Used to track blocks whose transactions were applied to the UTXO state as a
* part of a single ActivateBestChainStep call.
+ *
+ * This class also tracks transactions that are removed from the mempool as
+ * conflicts (per block) and can be used to pass all those transactions
+ * through SyncTransaction.
+ *
+ * This class assumes (and asserts) that the conflicted transactions for a given
+ * block are added via mempool callbacks prior to the BlockConnected() associated
+ * with those transactions. If any transactions are marked conflicted, it is
+ * assumed that an associated block will always be added.
+ *
+ * This class is single-use, once you call GetBlocksConnected() you have to throw
+ * it away and make a new one.
*/
-struct ConnectTrace {
- std::vector<std::pair<CBlockIndex*, std::shared_ptr<const CBlock> > > blocksConnected;
+class ConnectTrace {
+private:
+ std::vector<PerBlockConnectTrace> blocksConnected;
+ CTxMemPool &pool;
+
+public:
+ explicit ConnectTrace(CTxMemPool &_pool) : blocksConnected(1), pool(_pool) {
+ pool.NotifyEntryRemoved.connect(boost::bind(&ConnectTrace::NotifyEntryRemoved, this, _1, _2));
+ }
+
+ ~ConnectTrace() {
+ pool.NotifyEntryRemoved.disconnect(boost::bind(&ConnectTrace::NotifyEntryRemoved, this, _1, _2));
+ }
+
+ void BlockConnected(CBlockIndex* pindex, std::shared_ptr<const CBlock> pblock) {
+ assert(!blocksConnected.back().pindex);
+ assert(pindex);
+ assert(pblock);
+ blocksConnected.back().pindex = pindex;
+ blocksConnected.back().pblock = std::move(pblock);
+ blocksConnected.emplace_back();
+ }
+
+ std::vector<PerBlockConnectTrace>& GetBlocksConnected() {
+ // We always keep one extra block at the end of our list because
+ // blocks are added after all the conflicted transactions have
+ // been filled in. Thus, the last entry should always be an empty
+ // one waiting for the transactions from the next block. We pop
+ // the last entry here to make sure the list we return is sane.
+ assert(!blocksConnected.back().pindex);
+ assert(blocksConnected.back().conflictedTxs->empty());
+ blocksConnected.pop_back();
+ return blocksConnected;
+ }
+
+ void NotifyEntryRemoved(CTransactionRef txRemoved, MemPoolRemovalReason reason) {
+ assert(!blocksConnected.back().pindex);
+ if (reason == MemPoolRemovalReason::CONFLICT) {
+ blocksConnected.back().conflictedTxs->emplace_back(std::move(txRemoved));
+ }
+ }
};
/**
- * Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock
+ * Connect a new block to chainActive. pblock is either nullptr or a pointer to a CBlock
* corresponding to pindexNew, to bypass loading it again from disk.
*
- * The block is always added to connectTrace (either after loading from disk or by copying
- * pblock) - if that is not intended, care must be taken to remove the last entry in
- * blocksConnected in case of failure.
+ * The block is added to connectTrace if connection succeeds.
*/
-bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace)
+bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool)
{
assert(pindexNew->pprev == chainActive.Tip());
// Read block from disk.
int64_t nTime1 = GetTimeMicros();
+ std::shared_ptr<const CBlock> pthisBlock;
if (!pblock) {
std::shared_ptr<CBlock> pblockNew = std::make_shared<CBlock>();
- connectTrace.blocksConnected.emplace_back(pindexNew, pblockNew);
if (!ReadBlockFromDisk(*pblockNew, pindexNew, chainparams.GetConsensus()))
return AbortNode(state, "Failed to read block");
+ pthisBlock = pblockNew;
} else {
- connectTrace.blocksConnected.emplace_back(pindexNew, pblock);
+ pthisBlock = pblock;
}
- const CBlock& blockConnecting = *connectTrace.blocksConnected.back().second;
+ const CBlock& blockConnecting = *pthisBlock;
// Apply the block atomically to the chain state.
int64_t nTime2 = GetTimeMicros(); nTimeReadFromDisk += nTime2 - nTime1;
int64_t nTime3;
- LogPrint("bench", " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001);
+ LogPrint(BCLog::BENCH, " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * MILLI, nTimeReadFromDisk * MICRO);
{
CCoinsViewCache view(pcoinsTip);
bool rv = ConnectBlock(blockConnecting, state, pindexNew, view, chainparams);
@@ -2234,25 +2217,28 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
return error("ConnectTip(): ConnectBlock %s failed", pindexNew->GetBlockHash().ToString());
}
nTime3 = GetTimeMicros(); nTimeConnectTotal += nTime3 - nTime2;
- LogPrint("bench", " - Connect total: %.2fms [%.2fs]\n", (nTime3 - nTime2) * 0.001, nTimeConnectTotal * 0.000001);
+ LogPrint(BCLog::BENCH, " - Connect total: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime3 - nTime2) * MILLI, nTimeConnectTotal * MICRO, nTimeConnectTotal * MILLI / nBlocksTotal);
bool flushed = view.Flush();
assert(flushed);
}
int64_t nTime4 = GetTimeMicros(); nTimeFlush += nTime4 - nTime3;
- LogPrint("bench", " - Flush: %.2fms [%.2fs]\n", (nTime4 - nTime3) * 0.001, nTimeFlush * 0.000001);
+ LogPrint(BCLog::BENCH, " - Flush: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime4 - nTime3) * MILLI, nTimeFlush * MICRO, nTimeFlush * MILLI / nBlocksTotal);
// Write the chain state to disk, if necessary.
- if (!FlushStateToDisk(state, FLUSH_STATE_IF_NEEDED))
+ if (!FlushStateToDisk(chainparams, state, FLUSH_STATE_IF_NEEDED))
return false;
int64_t nTime5 = GetTimeMicros(); nTimeChainState += nTime5 - nTime4;
- LogPrint("bench", " - Writing chainstate: %.2fms [%.2fs]\n", (nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001);
+ LogPrint(BCLog::BENCH, " - Writing chainstate: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime5 - nTime4) * MILLI, nTimeChainState * MICRO, nTimeChainState * MILLI / nBlocksTotal);
// Remove conflicting transactions from the mempool.;
mempool.removeForBlock(blockConnecting.vtx, pindexNew->nHeight);
+ disconnectpool.removeForBlock(blockConnecting.vtx);
// Update chainActive & related variables.
UpdateTip(pindexNew, chainparams);
int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1;
- LogPrint("bench", " - Connect postprocess: %.2fms [%.2fs]\n", (nTime6 - nTime5) * 0.001, nTimePostConnect * 0.000001);
- LogPrint("bench", "- Connect block: %.2fms [%.2fs]\n", (nTime6 - nTime1) * 0.001, nTimeTotal * 0.000001);
+ LogPrint(BCLog::BENCH, " - Connect postprocess: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime6 - nTime5) * MILLI, nTimePostConnect * MICRO, nTimePostConnect * MILLI / nBlocksTotal);
+ LogPrint(BCLog::BENCH, "- Connect block: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime6 - nTime1) * MILLI, nTimeTotal * MICRO, nTimeTotal * MILLI / nBlocksTotal);
+
+ connectTrace.BlockConnected(pindexNew, std::move(pthisBlock));
return true;
}
@@ -2262,13 +2248,13 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
*/
static CBlockIndex* FindMostWorkChain() {
do {
- CBlockIndex *pindexNew = NULL;
+ CBlockIndex *pindexNew = nullptr;
// Find the best candidate header.
{
std::set<CBlockIndex*, CBlockIndexWorkComparator>::reverse_iterator it = setBlockIndexCandidates.rbegin();
if (it == setBlockIndexCandidates.rend())
- return NULL;
+ return nullptr;
pindexNew = *it;
}
@@ -2287,7 +2273,7 @@ static CBlockIndex* FindMostWorkChain() {
bool fMissingData = !(pindexTest->nStatus & BLOCK_HAVE_DATA);
if (fFailedChain || fMissingData) {
// Candidate chain is not usable (either invalid or missing data)
- if (fFailedChain && (pindexBestInvalid == NULL || pindexNew->nChainWork > pindexBestInvalid->nChainWork))
+ if (fFailedChain && (pindexBestInvalid == nullptr || pindexNew->nChainWork > pindexBestInvalid->nChainWork))
pindexBestInvalid = pindexNew;
CBlockIndex *pindexFailed = pindexNew;
// Remove the entire chain from the set.
@@ -2328,7 +2314,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.
+ * pblock is either nullptr or a pointer to a CBlock corresponding to pindexMostWork.
*/
static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace)
{
@@ -2338,9 +2324,14 @@ static bool ActivateBestChainStep(CValidationState& state, const CChainParams& c
// Disconnect active blocks which are no longer in the best chain.
bool fBlocksDisconnected = false;
+ DisconnectedBlockTransactions disconnectpool;
while (chainActive.Tip() && chainActive.Tip() != pindexFork) {
- if (!DisconnectTip(state, chainparams))
+ if (!DisconnectTip(state, chainparams, &disconnectpool)) {
+ // This is likely a fatal error, but keep the mempool consistent,
+ // just in case. Only remove from the mempool in this case.
+ UpdateMempoolForReorg(disconnectpool, false);
return false;
+ }
fBlocksDisconnected = true;
}
@@ -2362,8 +2353,8 @@ static bool ActivateBestChainStep(CValidationState& state, const CChainParams& c
nHeight = nTargetHeight;
// Connect new blocks.
- BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) {
- if (!ConnectTip(state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : std::shared_ptr<const CBlock>(), connectTrace)) {
+ for (CBlockIndex *pindexConnect : reverse_iterate(vpindexToConnect)) {
+ if (!ConnectTip(state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : std::shared_ptr<const CBlock>(), connectTrace, disconnectpool)) {
if (state.IsInvalid()) {
// The block violates a consensus rule.
if (!state.CorruptionPossible())
@@ -2371,11 +2362,12 @@ static bool ActivateBestChainStep(CValidationState& state, const CChainParams& c
state = CValidationState();
fInvalidFound = true;
fContinue = false;
- // If we didn't actually connect the block, don't notify listeners about it
- connectTrace.blocksConnected.pop_back();
break;
} else {
// A system error occurred (disk space, database error, ...).
+ // Make the mempool consistent with the current tip, just in case
+ // any observers try to use it before shutdown.
+ UpdateMempoolForReorg(disconnectpool, false);
return false;
}
} else {
@@ -2390,8 +2382,9 @@ static bool ActivateBestChainStep(CValidationState& state, const CChainParams& c
}
if (fBlocksDisconnected) {
- mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS);
- LimitMempoolSize(mempool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);
+ // If any blocks were disconnected, disconnectpool may be non empty. Add
+ // any disconnected transactions back to the mempool.
+ UpdateMempoolForReorg(disconnectpool, true);
}
mempool.check(pcoinsTip);
@@ -2407,8 +2400,8 @@ static bool ActivateBestChainStep(CValidationState& state, const CChainParams& c
static void NotifyHeaderTip() {
bool fNotify = false;
bool fInitialBlockDownload = false;
- static CBlockIndex* pindexHeaderOld = NULL;
- CBlockIndex* pindexHeader = NULL;
+ static CBlockIndex* pindexHeaderOld = nullptr;
+ CBlockIndex* pindexHeader = nullptr;
{
LOCK(cs_main);
pindexHeader = pindexBestHeader;
@@ -2427,7 +2420,7 @@ static void NotifyHeaderTip() {
/**
* Make the best chain active, in multiple steps. The result is either failure
- * or an activated best chain. pblock is either NULL or a pointer to a block
+ * or an activated best chain. pblock is either nullptr or a pointer to a block
* that is already loaded (to avoid loading it again from disk).
*/
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
@@ -2436,25 +2429,27 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
// us in the middle of ProcessNewBlock - do not assume pblock is set
// sanely for performance or correctness!
- CBlockIndex *pindexMostWork = NULL;
- CBlockIndex *pindexNewTip = NULL;
+ CBlockIndex *pindexMostWork = nullptr;
+ CBlockIndex *pindexNewTip = nullptr;
+ int nStopAtHeight = gArgs.GetArg("-stopatheight", DEFAULT_STOPATHEIGHT);
do {
boost::this_thread::interruption_point();
if (ShutdownRequested())
break;
const CBlockIndex *pindexFork;
- ConnectTrace connectTrace;
bool fInitialDownload;
{
LOCK(cs_main);
+ ConnectTrace connectTrace(mempool); // Destructed before cs_main is unlocked
+
CBlockIndex *pindexOldTip = chainActive.Tip();
- if (pindexMostWork == NULL) {
+ if (pindexMostWork == nullptr) {
pindexMostWork = FindMostWorkChain();
}
// Whether we have anything to do at all.
- if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip())
+ if (pindexMostWork == nullptr || pindexMostWork == chainActive.Tip())
return true;
bool fInvalidFound = false;
@@ -2464,25 +2459,21 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
if (fInvalidFound) {
// Wipe cache, we may need another branch now.
- pindexMostWork = NULL;
+ pindexMostWork = nullptr;
}
pindexNewTip = chainActive.Tip();
pindexFork = chainActive.FindFork(pindexOldTip);
fInitialDownload = IsInitialBlockDownload();
+
+ for (const PerBlockConnectTrace& trace : connectTrace.GetBlocksConnected()) {
+ assert(trace.pblock && trace.pindex);
+ GetMainSignals().BlockConnected(trace.pblock, trace.pindex, *trace.conflictedTxs);
+ }
}
// When we reach this point, we switched to a new tip (stored in pindexNewTip).
// Notifications/callbacks that can run without cs_main
- // throw all transactions though the signal-interface
- // while _not_ holding the cs_main lock
- for (const auto& pair : connectTrace.blocksConnected) {
- assert(pair.second);
- const CBlock& block = *(pair.second);
- for (unsigned int i = 0; i < block.vtx.size(); i++)
- GetMainSignals().SyncTransaction(*block.vtx[i], pair.first, i);
- }
-
// Notify external listeners about the new tip.
GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload);
@@ -2490,11 +2481,13 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
if (pindexFork != pindexNewTip) {
uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip);
}
+
+ if (nStopAtHeight && pindexNewTip && pindexNewTip->nHeight >= nStopAtHeight) StartShutdown();
} while (pindexNewTip != pindexMostWork);
CheckBlockIndex(chainparams.GetConsensus());
// Write changes periodically to disk, after relay.
- if (!FlushStateToDisk(state, FLUSH_STATE_PERIODIC)) {
+ if (!FlushStateToDisk(chainparams, state, FLUSH_STATE_PERIODIC)) {
return false;
}
@@ -2540,6 +2533,7 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C
setDirtyBlockIndex.insert(pindex);
setBlockIndexCandidates.erase(pindex);
+ DisconnectedBlockTransactions disconnectpool;
while (chainActive.Contains(pindex)) {
CBlockIndex *pindexWalk = chainActive.Tip();
pindexWalk->nStatus |= BLOCK_FAILED_CHILD;
@@ -2547,13 +2541,17 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C
setBlockIndexCandidates.erase(pindexWalk);
// ActivateBestChain considers blocks already in chainActive
// unconditionally valid already, so force disconnect away from it.
- if (!DisconnectTip(state, chainparams)) {
- mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS);
+ if (!DisconnectTip(state, chainparams, &disconnectpool)) {
+ // It's probably hopeless to try to make the mempool consistent
+ // here if DisconnectTip failed, but we can try.
+ UpdateMempoolForReorg(disconnectpool, false);
return false;
}
}
- LimitMempoolSize(mempool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);
+ // DisconnectTip will add transactions to disconnectpool; try to add these
+ // back to the mempool.
+ UpdateMempoolForReorg(disconnectpool, true);
// The resulting new best tip may not be in setBlockIndexCandidates anymore, so
// add it again.
@@ -2566,7 +2564,6 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C
}
InvalidChainFound(pindex);
- mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS);
uiInterface.NotifyBlockTip(IsInitialBlockDownload(), pindex->pprev);
return true;
}
@@ -2587,14 +2584,14 @@ bool ResetBlockFailureFlags(CBlockIndex *pindex) {
}
if (it->second == pindexBestInvalid) {
// Reset invalid block marker if it was pointing to one of those.
- pindexBestInvalid = NULL;
+ pindexBestInvalid = nullptr;
}
}
it++;
}
// Remove the invalidity flag from all ancestors too.
- while (pindex != NULL) {
+ while (pindex != nullptr) {
if (pindex->nStatus & BLOCK_FAILED_MASK) {
pindex->nStatus &= ~BLOCK_FAILED_MASK;
setDirtyBlockIndex.insert(pindex);
@@ -2604,7 +2601,7 @@ bool ResetBlockFailureFlags(CBlockIndex *pindex) {
return true;
}
-CBlockIndex* AddToBlockIndex(const CBlockHeader& block)
+static CBlockIndex* AddToBlockIndex(const CBlockHeader& block)
{
// Check for duplicate
uint256 hash = block.GetHash();
@@ -2619,7 +2616,7 @@ CBlockIndex* AddToBlockIndex(const CBlockHeader& block)
// to avoid miners withholding blocks but broadcasting headers, to get a
// competitive advantage.
pindexNew->nSequenceId = 0;
- BlockMap::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
+ BlockMap::iterator mi = mapBlockIndex.insert(std::make_pair(hash, pindexNew)).first;
pindexNew->phashBlock = &((*mi).first);
BlockMap::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock);
if (miPrev != mapBlockIndex.end())
@@ -2631,7 +2628,7 @@ CBlockIndex* AddToBlockIndex(const CBlockHeader& block)
pindexNew->nTimeMax = (pindexNew->pprev ? std::max(pindexNew->pprev->nTimeMax, pindexNew->nTime) : pindexNew->nTime);
pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockProof(*pindexNew);
pindexNew->RaiseValidity(BLOCK_VALID_TREE);
- if (pindexBestHeader == NULL || pindexBestHeader->nChainWork < pindexNew->nChainWork)
+ if (pindexBestHeader == nullptr || pindexBestHeader->nChainWork < pindexNew->nChainWork)
pindexBestHeader = pindexNew;
setDirtyBlockIndex.insert(pindexNew);
@@ -2640,7 +2637,7 @@ CBlockIndex* AddToBlockIndex(const CBlockHeader& block)
}
/** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). */
-bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos)
+static bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos, const Consensus::Params& consensusParams)
{
pindexNew->nTx = block.vtx.size();
pindexNew->nChainTx = 0;
@@ -2648,15 +2645,15 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
pindexNew->nDataPos = pos.nPos;
pindexNew->nUndoPos = 0;
pindexNew->nStatus |= BLOCK_HAVE_DATA;
- if (IsWitnessEnabled(pindexNew->pprev, Params().GetConsensus())) {
+ if (IsWitnessEnabled(pindexNew->pprev, consensusParams)) {
pindexNew->nStatus |= BLOCK_OPT_WITNESS;
}
pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS);
setDirtyBlockIndex.insert(pindexNew);
- if (pindexNew->pprev == NULL || pindexNew->pprev->nChainTx) {
+ if (pindexNew->pprev == nullptr || pindexNew->pprev->nChainTx) {
// If pindexNew is the genesis block or all parents are BLOCK_VALID_TRANSACTIONS.
- deque<CBlockIndex*> queue;
+ std::deque<CBlockIndex*> queue;
queue.push_back(pindexNew);
// Recursively process any descendant blocks that now may be eligible to be connected.
@@ -2668,7 +2665,7 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
LOCK(cs_nBlockSequenceId);
pindex->nSequenceId = nBlockSequenceId++;
}
- if (chainActive.Tip() == NULL || !setBlockIndexCandidates.value_comp()(pindex, chainActive.Tip())) {
+ if (chainActive.Tip() == nullptr || !setBlockIndexCandidates.value_comp()(pindex, chainActive.Tip())) {
setBlockIndexCandidates.insert(pindex);
}
std::pair<std::multimap<CBlockIndex*, CBlockIndex*>::iterator, std::multimap<CBlockIndex*, CBlockIndex*>::iterator> range = mapBlocksUnlinked.equal_range(pindex);
@@ -2688,7 +2685,7 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
return true;
}
-bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown = false)
+static bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown = false)
{
LOCK(cs_LastBlockFile);
@@ -2745,7 +2742,7 @@ bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAdd
return true;
}
-bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize)
+static bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize)
{
pos.nFile = nFile;
@@ -2776,7 +2773,7 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne
return true;
}
-bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW)
+static bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true)
{
// Check proof of work matches claimed amount
if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, consensusParams))
@@ -2818,7 +2815,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
// checks that use witness data may be performed here.
// Size limits
- if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_BASE_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) > MAX_BLOCK_BASE_SIZE)
+ if (block.vtx.empty() || block.vtx.size() * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT)
return state.DoS(100, false, REJECT_INVALID, "bad-blk-length", false, "size limits failed");
// First transaction must be coinbase, the rest must not be
@@ -2848,20 +2845,6 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
return true;
}
-static bool CheckIndexAgainstCheckpoint(const CBlockIndex* pindexPrev, CValidationState& state, const CChainParams& chainparams, const uint256& hash)
-{
- if (*pindexPrev->phashBlock == chainparams.GetConsensus().hashGenesisBlock)
- return true;
-
- 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 IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params)
{
LOCK(cs_main);
@@ -2873,9 +2856,11 @@ bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& pa
static int GetWitnessCommitmentIndex(const CBlock& block)
{
int commitpos = -1;
- for (size_t o = 0; o < block.vtx[0]->vout.size(); o++) {
- if (block.vtx[0]->vout[o].scriptPubKey.size() >= 38 && block.vtx[0]->vout[o].scriptPubKey[0] == OP_RETURN && block.vtx[0]->vout[o].scriptPubKey[1] == 0x24 && block.vtx[0]->vout[o].scriptPubKey[2] == 0xaa && block.vtx[0]->vout[o].scriptPubKey[3] == 0x21 && block.vtx[0]->vout[o].scriptPubKey[4] == 0xa9 && block.vtx[0]->vout[o].scriptPubKey[5] == 0xed) {
- commitpos = o;
+ if (!block.vtx.empty()) {
+ for (size_t o = 0; o < block.vtx[0]->vout.size(); o++) {
+ if (block.vtx[0]->vout[o].scriptPubKey.size() >= 38 && block.vtx[0]->vout[o].scriptPubKey[0] == OP_RETURN && block.vtx[0]->vout[o].scriptPubKey[1] == 0x24 && block.vtx[0]->vout[o].scriptPubKey[2] == 0xaa && block.vtx[0]->vout[o].scriptPubKey[3] == 0x21 && block.vtx[0]->vout[o].scriptPubKey[4] == 0xa9 && block.vtx[0]->vout[o].scriptPubKey[5] == 0xed) {
+ commitpos = o;
+ }
}
}
return commitpos;
@@ -2900,8 +2885,8 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
std::vector<unsigned char> ret(32, 0x00);
if (consensusParams.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout != 0) {
if (commitpos == -1) {
- uint256 witnessroot = BlockWitnessMerkleRoot(block, NULL);
- CHash256().Write(witnessroot.begin(), 32).Write(&ret[0], 32).Finalize(witnessroot.begin());
+ uint256 witnessroot = BlockWitnessMerkleRoot(block, nullptr);
+ CHash256().Write(witnessroot.begin(), 32).Write(ret.data(), 32).Finalize(witnessroot.begin());
CTxOut out;
out.nValue = 0;
out.scriptPubKey.resize(38);
@@ -2922,19 +2907,35 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
return commitment;
}
-bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev, int64_t nAdjustedTime)
+/** Context-dependent validity checks.
+ * By "context", we mean only the previous block headers, but not the UTXO
+ * set; UTXO-related validity checks are done in ConnectBlock(). */
+static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime)
{
- const int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1;
+ assert(pindexPrev != nullptr);
+ const int nHeight = pindexPrev->nHeight + 1;
+
// Check proof of work
+ const Consensus::Params& consensusParams = params.GetConsensus();
if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))
return state.DoS(100, false, REJECT_INVALID, "bad-diffbits", false, "incorrect proof of work");
+ // Check against checkpoints
+ if (fCheckpointsEnabled) {
+ // Don't accept any forks from the main chain prior to last checkpoint.
+ // GetLastCheckpoint finds the last checkpoint in MapCheckpoints that's in our
+ // MapBlockIndex.
+ CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(params.Checkpoints());
+ if (pcheckpoint && nHeight < pcheckpoint->nHeight)
+ return state.DoS(100, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight), REJECT_CHECKPOINT, "bad-fork-prior-to-checkpoint");
+ }
+
// Check timestamp against prev
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast())
return state.Invalid(false, REJECT_INVALID, "time-too-old", "block's timestamp is too early");
// Check timestamp
- if (block.GetBlockTime() > nAdjustedTime + 2 * 60 * 60)
+ if (block.GetBlockTime() > nAdjustedTime + MAX_FUTURE_BLOCK_TIME)
return state.Invalid(false, REJECT_INVALID, "time-too-new", "block timestamp too far in the future");
// Reject outdated version blocks when 95% (75% on testnet) of the network has upgraded:
@@ -2948,9 +2949,9 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
return true;
}
-bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
+static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
{
- const int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1;
+ const int nHeight = pindexPrev == nullptr ? 0 : pindexPrev->nHeight + 1;
// Start enforcing BIP113 (Median Time Past) using versionbits logic.
int nLockTimeFlags = 0;
@@ -3009,8 +3010,8 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co
// No witness data is allowed in blocks that don't commit to witness data, as this would otherwise leave room for spam
if (!fHaveWitness) {
- for (size_t i = 0; i < block.vtx.size(); i++) {
- if (block.vtx[i]->HasWitness()) {
+ for (const auto& tx : block.vtx) {
+ if (tx->HasWitness()) {
return state.DoS(100, false, REJECT_INVALID, "unexpected-witness", true, strprintf("%s : unexpected witness data found", __func__));
}
}
@@ -3035,7 +3036,7 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state
// Check for duplicate
uint256 hash = block.GetHash();
BlockMap::iterator miSelf = mapBlockIndex.find(hash);
- CBlockIndex *pindex = NULL;
+ CBlockIndex *pindex = nullptr;
if (hash != chainparams.GetConsensus().hashGenesisBlock) {
if (miSelf != mapBlockIndex.end()) {
@@ -3052,22 +3053,17 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state
return error("%s: Consensus::CheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state));
// Get prev block index
- CBlockIndex* pindexPrev = NULL;
+ CBlockIndex* pindexPrev = nullptr;
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");
+ return state.DoS(10, error("%s: prev block not found", __func__), 0, "prev-blk-not-found");
pindexPrev = (*mi).second;
if (pindexPrev->nStatus & BLOCK_FAILED_MASK)
return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk");
-
- assert(pindexPrev);
- if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, hash))
- return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, state.GetRejectReason().c_str());
-
- if (!ContextualCheckBlockHeader(block, state, chainparams.GetConsensus(), pindexPrev, GetAdjustedTime()))
+ if (!ContextualCheckBlockHeader(block, state, chainparams, pindexPrev, GetAdjustedTime()))
return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state));
}
- if (pindex == NULL)
+ if (pindex == nullptr)
pindex = AddToBlockIndex(block);
if (ppindex)
@@ -3084,7 +3080,7 @@ bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidatio
{
LOCK(cs_main);
for (const CBlockHeader& header : headers) {
- CBlockIndex *pindex = NULL; // Use a temp pindex instead of ppindex to avoid a const_cast
+ CBlockIndex *pindex = nullptr; // Use a temp pindex instead of ppindex to avoid a const_cast
if (!AcceptBlockHeader(header, state, chainparams, &pindex)) {
return false;
}
@@ -3097,7 +3093,7 @@ bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidatio
return true;
}
-/** Store block on disk. If dbp is non-NULL, the file is known to already reside on disk */
+/** Store block on disk. If dbp is non-nullptr, the file is known to already reside on disk */
static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp, bool* fNewBlock)
{
const CBlock& block = *pblock;
@@ -3105,7 +3101,7 @@ static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidation
if (fNewBlock) *fNewBlock = false;
AssertLockHeld(cs_main);
- CBlockIndex *pindexDummy = NULL;
+ CBlockIndex *pindexDummy = nullptr;
CBlockIndex *&pindex = ppindex ? *ppindex : pindexDummy;
if (!AcceptBlockHeader(block, state, chainparams, &pindex))
@@ -3124,7 +3120,7 @@ static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidation
bool fTooFarAhead = (pindex->nHeight > int(chainActive.Height() + MIN_BLOCKS_TO_KEEP));
// TODO: Decouple this function from the block download logic by removing fRequested
- // This requires some new chain datastructure to efficiently look up if a
+ // This requires some new chain data structure to efficiently look up if a
// block is in a chain leading to a candidate for best tip, despite not
// being such a candidate itself.
@@ -3138,7 +3134,7 @@ static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidation
}
if (fNewBlock) *fNewBlock = true;
- if (!CheckBlock(block, state, chainparams.GetConsensus(), GetAdjustedTime()) ||
+ if (!CheckBlock(block, state, chainparams.GetConsensus()) ||
!ContextualCheckBlock(block, state, chainparams.GetConsensus(), pindex->pprev)) {
if (state.IsInvalid() && !state.CorruptionPossible()) {
pindex->nStatus |= BLOCK_FAILED_VALID;
@@ -3158,21 +3154,21 @@ static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidation
try {
unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
CDiskBlockPos blockPos;
- if (dbp != NULL)
+ if (dbp != nullptr)
blockPos = *dbp;
- if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, block.GetBlockTime(), dbp != NULL))
+ if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, block.GetBlockTime(), dbp != nullptr))
return error("AcceptBlock(): FindBlockPos failed");
- if (dbp == NULL)
+ if (dbp == nullptr)
if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart()))
AbortNode(state, "Failed to write block");
- if (!ReceivedBlockTransactions(block, state, pindex, blockPos))
+ if (!ReceivedBlockTransactions(block, state, pindex, blockPos, chainparams.GetConsensus()))
return error("AcceptBlock(): ReceivedBlockTransactions failed");
} catch (const std::runtime_error& e) {
return AbortNode(state, std::string("System error: ") + e.what());
}
if (fCheckForPruning)
- FlushStateToDisk(state, FLUSH_STATE_NONE); // we just allocated more disk space for block files
+ FlushStateToDisk(chainparams, state, FLUSH_STATE_NONE); // we just allocated more disk space for block files
return true;
}
@@ -3180,17 +3176,23 @@ static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidation
bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock> pblock, bool fForceProcessing, bool *fNewBlock)
{
{
- LOCK(cs_main);
-
- // Store to disk
- CBlockIndex *pindex = NULL;
+ CBlockIndex *pindex = nullptr;
if (fNewBlock) *fNewBlock = false;
CValidationState state;
- bool ret = AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, NULL, fNewBlock);
+ // Ensure that CheckBlock() passes before calling AcceptBlock, as
+ // belt-and-suspenders.
+ bool ret = CheckBlock(*pblock, state, chainparams.GetConsensus());
+
+ LOCK(cs_main);
+
+ if (ret) {
+ // Store to disk
+ ret = AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, nullptr, fNewBlock);
+ }
CheckBlockIndex(chainparams.GetConsensus());
if (!ret) {
GetMainSignals().BlockChecked(*pblock, state);
- return error("%s: AcceptBlock FAILED", __func__);
+ return error("%s: AcceptBlock FAILED (%s)", __func__, state.GetDebugMessage());
}
}
@@ -3207,16 +3209,13 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams,
{
AssertLockHeld(cs_main);
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);
indexDummy.pprev = pindexPrev;
indexDummy.nHeight = pindexPrev->nHeight + 1;
// NOTE: CheckBlockHeader is called by CheckBlock
- if (!ContextualCheckBlockHeader(block, state, chainparams.GetConsensus(), pindexPrev, GetAdjustedTime()))
+ if (!ContextualCheckBlockHeader(block, state, chainparams, pindexPrev, GetAdjustedTime()))
return error("%s: Consensus::ContextualCheckBlockHeader: %s", __func__, FormatStateMessage(state));
if (!CheckBlock(block, state, chainparams.GetConsensus(), fCheckPOW, fCheckMerkleRoot))
return error("%s: Consensus::CheckBlock: %s", __func__, FormatStateMessage(state));
@@ -3234,10 +3233,10 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams,
*/
/* Calculate the amount of disk space the block & undo files currently use */
-uint64_t CalculateCurrentUsage()
+static uint64_t CalculateCurrentUsage()
{
uint64_t retval = 0;
- BOOST_FOREACH(const CBlockFileInfo &file, vinfoBlockFile) {
+ for (const CBlockFileInfo &file : vinfoBlockFile) {
retval += file.nSize + file.nUndoSize;
}
return retval;
@@ -3276,27 +3275,27 @@ void PruneOneBlockFile(const int fileNumber)
}
-void UnlinkPrunedFiles(std::set<int>& setFilesToPrune)
+void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune)
{
- for (set<int>::iterator it = setFilesToPrune.begin(); it != setFilesToPrune.end(); ++it) {
+ for (std::set<int>::iterator it = setFilesToPrune.begin(); it != setFilesToPrune.end(); ++it) {
CDiskBlockPos pos(*it, 0);
- boost::filesystem::remove(GetBlockPosFilename(pos, "blk"));
- boost::filesystem::remove(GetBlockPosFilename(pos, "rev"));
+ fs::remove(GetBlockPosFilename(pos, "blk"));
+ fs::remove(GetBlockPosFilename(pos, "rev"));
LogPrintf("Prune: %s deleted blk/rev (%05u)\n", __func__, *it);
}
}
/* Calculate the block/rev files to delete based on height specified by user with RPC command pruneblockchain */
-void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight)
+static void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight)
{
assert(fPruneMode && nManualPruneHeight > 0);
LOCK2(cs_main, cs_LastBlockFile);
- if (chainActive.Tip() == NULL)
+ if (chainActive.Tip() == nullptr)
return;
// last block to prune is the lesser of (user-specified height, MIN_BLOCKS_TO_KEEP from the tip)
- unsigned int nLastBlockWeCanPrune = min((unsigned)nManualPruneHeight, chainActive.Tip()->nHeight - MIN_BLOCKS_TO_KEEP);
+ unsigned int nLastBlockWeCanPrune = std::min((unsigned)nManualPruneHeight, chainActive.Tip()->nHeight - MIN_BLOCKS_TO_KEEP);
int count=0;
for (int fileNumber = 0; fileNumber < nLastBlockFile; fileNumber++) {
if (vinfoBlockFile[fileNumber].nSize == 0 || vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune)
@@ -3312,14 +3311,29 @@ void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeig
void PruneBlockFilesManual(int nManualPruneHeight)
{
CValidationState state;
- FlushStateToDisk(state, FLUSH_STATE_NONE, nManualPruneHeight);
+ const CChainParams& chainparams = Params();
+ FlushStateToDisk(chainparams, state, FLUSH_STATE_NONE, nManualPruneHeight);
}
-/* Calculate the block/rev files that should be deleted to remain under target*/
-void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight)
+/**
+ * Prune block and undo files (blk???.dat and undo???.dat) so that the disk space used is less than a user-defined target.
+ * The user sets the target (in MB) on the command line or in config file. This will be run on startup and whenever new
+ * space is allocated in a block or undo file, staying below the target. Changing back to unpruned requires a reindex
+ * (which in this case means the blockchain must be re-downloaded.)
+ *
+ * Pruning functions are called from FlushStateToDisk when the global fCheckForPruning flag has been set.
+ * Block and undo files are deleted in lock-step (when blk00003.dat is deleted, so is rev00003.dat.)
+ * Pruning cannot take place until the longest chain is at least a certain length (100000 on mainnet, 1000 on testnet, 1000 on regtest).
+ * Pruning will never delete a block within a defined distance (currently 288) from the active chain's tip.
+ * The block index is updated by unsetting HAVE_DATA and HAVE_UNDO for any blocks that were stored in the deleted files.
+ * A db flag records the fact that at least some block files have been pruned.
+ *
+ * @param[out] setFilesToPrune The set of file indices that can be unlinked will be returned
+ */
+static void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight)
{
LOCK2(cs_main, cs_LastBlockFile);
- if (chainActive.Tip() == NULL || nPruneTarget == 0) {
+ if (chainActive.Tip() == nullptr || nPruneTarget == 0) {
return;
}
if ((uint64_t)chainActive.Tip()->nHeight <= nPruneAfterHeight) {
@@ -3357,7 +3371,7 @@ void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight
}
}
- LogPrint("prune", "Prune: target=%dMiB actual=%dMiB diff=%dMiB max_prune_height=%d removed %d blk/rev pairs\n",
+ LogPrint(BCLog::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,
nLastBlockWeCanPrune, count);
@@ -3365,7 +3379,7 @@ void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight
bool CheckDiskSpace(uint64_t nAdditionalBytes)
{
- uint64_t nFreeBytesAvailable = boost::filesystem::space(GetDataDir()).available;
+ uint64_t nFreeBytesAvailable = fs::space(GetDataDir()).available;
// Check for nMinDiskSpace bytes (currently 50MB)
if (nFreeBytesAvailable < nMinDiskSpace + nAdditionalBytes)
@@ -3374,24 +3388,24 @@ bool CheckDiskSpace(uint64_t nAdditionalBytes)
return true;
}
-FILE* OpenDiskFile(const CDiskBlockPos &pos, const char *prefix, bool fReadOnly)
+static FILE* OpenDiskFile(const CDiskBlockPos &pos, const char *prefix, bool fReadOnly)
{
if (pos.IsNull())
- return NULL;
- boost::filesystem::path path = GetBlockPosFilename(pos, prefix);
- boost::filesystem::create_directories(path.parent_path());
- FILE* file = fopen(path.string().c_str(), "rb+");
+ return nullptr;
+ fs::path path = GetBlockPosFilename(pos, prefix);
+ fs::create_directories(path.parent_path());
+ FILE* file = fsbridge::fopen(path, "rb+");
if (!file && !fReadOnly)
- file = fopen(path.string().c_str(), "wb+");
+ file = fsbridge::fopen(path, "wb+");
if (!file) {
LogPrintf("Unable to open file %s\n", path.string());
- return NULL;
+ return nullptr;
}
if (pos.nPos) {
if (fseek(file, pos.nPos, SEEK_SET)) {
LogPrintf("Unable to seek to position %u of %s\n", pos.nPos, path.string());
fclose(file);
- return NULL;
+ return nullptr;
}
}
return file;
@@ -3401,11 +3415,12 @@ FILE* OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly) {
return OpenDiskFile(pos, "blk", fReadOnly);
}
-FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly) {
+/** Open an undo file (rev?????.dat) */
+static FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly) {
return OpenDiskFile(pos, "rev", fReadOnly);
}
-boost::filesystem::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix)
+fs::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix)
{
return GetDataDir() / "blocks" / strprintf("%s%05u.dat", prefix, pos.nFile);
}
@@ -3413,7 +3428,7 @@ boost::filesystem::path GetBlockPosFilename(const CDiskBlockPos &pos, const char
CBlockIndex * InsertBlockIndex(uint256 hash)
{
if (hash.IsNull())
- return NULL;
+ return nullptr;
// Return existing
BlockMap::iterator mi = mapBlockIndex.find(hash);
@@ -3423,8 +3438,8 @@ CBlockIndex * InsertBlockIndex(uint256 hash)
// Create new
CBlockIndex* pindexNew = new CBlockIndex();
if (!pindexNew)
- throw runtime_error(std::string(__func__) + ": new CBlockIndex failed");
- mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
+ throw std::runtime_error(std::string(__func__) + ": new CBlockIndex failed");
+ mi = mapBlockIndex.insert(std::make_pair(hash, pindexNew)).first;
pindexNew->phashBlock = &((*mi).first);
return pindexNew;
@@ -3432,21 +3447,21 @@ CBlockIndex * InsertBlockIndex(uint256 hash)
bool static LoadBlockIndexDB(const CChainParams& chainparams)
{
- if (!pblocktree->LoadBlockIndexGuts(InsertBlockIndex))
+ if (!pblocktree->LoadBlockIndexGuts(chainparams.GetConsensus(), InsertBlockIndex))
return false;
boost::this_thread::interruption_point();
// Calculate nChainWork
- vector<pair<int, CBlockIndex*> > vSortedByHeight;
+ std::vector<std::pair<int, CBlockIndex*> > vSortedByHeight;
vSortedByHeight.reserve(mapBlockIndex.size());
- BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex)
+ for (const std::pair<uint256, CBlockIndex*>& item : mapBlockIndex)
{
CBlockIndex* pindex = item.second;
- vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex));
+ vSortedByHeight.push_back(std::make_pair(pindex->nHeight, pindex));
}
sort(vSortedByHeight.begin(), vSortedByHeight.end());
- BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight)
+ for (const std::pair<int, CBlockIndex*>& item : vSortedByHeight)
{
CBlockIndex* pindex = item.second;
pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex);
@@ -3465,13 +3480,13 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams)
pindex->nChainTx = pindex->nTx;
}
}
- if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->nChainTx || pindex->pprev == NULL))
+ if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->nChainTx || pindex->pprev == nullptr))
setBlockIndexCandidates.insert(pindex);
if (pindex->nStatus & BLOCK_FAILED_MASK && (!pindexBestInvalid || pindex->nChainWork > pindexBestInvalid->nChainWork))
pindexBestInvalid = pindex;
if (pindex->pprev)
pindex->BuildSkip();
- if (pindex->IsValid(BLOCK_VALID_TREE) && (pindexBestHeader == NULL || CBlockIndexWorkComparator()(pindexBestHeader, pindex)))
+ if (pindex->IsValid(BLOCK_VALID_TREE) && (pindexBestHeader == nullptr || CBlockIndexWorkComparator()(pindexBestHeader, pindex)))
pindexBestHeader = pindex;
}
@@ -3494,8 +3509,8 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams)
// Check presence of blk files
LogPrintf("Checking all blk files are present...\n");
- set<int> setBlkDataFiles;
- BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex)
+ std::set<int> setBlkDataFiles;
+ for (const std::pair<uint256, CBlockIndex*>& item : mapBlockIndex)
{
CBlockIndex* pindex = item.second;
if (pindex->nStatus & BLOCK_HAVE_DATA) {
@@ -3518,54 +3533,68 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams)
// Check whether we need to continue reindexing
bool fReindexing = false;
pblocktree->ReadReindexing(fReindexing);
- fReindex |= fReindexing;
+ if(fReindexing) fReindex = true;
// Check whether we have a transaction index
pblocktree->ReadFlag("txindex", fTxIndex);
LogPrintf("%s: transaction index %s\n", __func__, fTxIndex ? "enabled" : "disabled");
+ return true;
+}
+
+bool LoadChainTip(const CChainParams& chainparams)
+{
+ if (chainActive.Tip() && chainActive.Tip()->GetBlockHash() == pcoinsTip->GetBestBlock()) return true;
+
+ if (pcoinsTip->GetBestBlock().IsNull() && mapBlockIndex.size() == 1) {
+ // In case we just added the genesis block, connect it now, so
+ // that we always have a chainActive.Tip() when we return.
+ LogPrintf("%s: Connecting genesis block...\n", __func__);
+ CValidationState state;
+ if (!ActivateBestChain(state, chainparams)) {
+ return false;
+ }
+ }
+
// Load pointer to end of best chain
BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
if (it == mapBlockIndex.end())
- return true;
+ return false;
chainActive.SetTip(it->second);
PruneBlockIndexCandidates();
- LogPrintf("%s: hashBestChain=%s height=%d date=%s progress=%f\n", __func__,
+ LogPrintf("Loaded best chain: hashBestChain=%s height=%d date=%s progress=%f\n",
chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(),
DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()),
GuessVerificationProgress(chainparams.TxData(), chainActive.Tip()));
-
return true;
}
CVerifyDB::CVerifyDB()
{
- uiInterface.ShowProgress(_("Verifying blocks..."), 0);
+ uiInterface.ShowProgress(_("Verifying blocks..."), 0, false);
}
CVerifyDB::~CVerifyDB()
{
- uiInterface.ShowProgress("", 100);
+ uiInterface.ShowProgress("", 100, false);
}
bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, int nCheckLevel, int nCheckDepth)
{
LOCK(cs_main);
- if (chainActive.Tip() == NULL || chainActive.Tip()->pprev == NULL)
+ if (chainActive.Tip() == nullptr || chainActive.Tip()->pprev == nullptr)
return true;
// Verify blocks in the best chain
- if (nCheckDepth <= 0)
- nCheckDepth = 1000000000; // suffices until the year 19000
- if (nCheckDepth > chainActive.Height())
+ if (nCheckDepth <= 0 || nCheckDepth > chainActive.Height())
nCheckDepth = chainActive.Height();
nCheckLevel = std::max(0, std::min(4, nCheckLevel));
LogPrintf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel);
CCoinsViewCache coins(coinsview);
CBlockIndex* pindexState = chainActive.Tip();
- CBlockIndex* pindexFailure = NULL;
+ CBlockIndex* pindexFailure = nullptr;
int nGoodTransactions = 0;
CValidationState state;
int reportDone = 0;
@@ -3579,7 +3608,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
LogPrintf("[%d%%]...", percentageDone);
reportDone = percentageDone/10;
}
- uiInterface.ShowProgress(_("Verifying blocks..."), percentageDone);
+ uiInterface.ShowProgress(_("Verifying blocks..."), percentageDone, false);
if (pindex->nHeight < chainActive.Height()-nCheckDepth)
break;
if (fPruneMode && !(pindex->nStatus & BLOCK_HAVE_DATA)) {
@@ -3593,7 +3622,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
// check level 1: verify block validity
if (nCheckLevel >= 1 && !CheckBlock(block, state, chainparams.GetConsensus()))
- return error("%s: *** found bad block at %d, hash=%s (%s)\n", __func__,
+ return error("%s: *** found bad block at %d, hash=%s (%s)\n", __func__,
pindex->nHeight, pindex->GetBlockHash().ToString(), FormatStateMessage(state));
// check level 2: verify undo validity
if (nCheckLevel >= 2 && pindex) {
@@ -3606,15 +3635,18 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
}
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks
if (nCheckLevel >= 3 && pindex == pindexState && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) {
- bool fClean = true;
- if (!DisconnectBlock(block, state, pindex, coins, &fClean))
+ assert(coins.GetBestBlock() == pindex->GetBlockHash());
+ DisconnectResult res = DisconnectBlock(block, pindex, coins);
+ if (res == DISCONNECT_FAILED) {
return error("VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
+ }
pindexState = pindex->pprev;
- if (!fClean) {
+ if (res == DISCONNECT_UNCLEAN) {
nGoodTransactions = 0;
pindexFailure = pindex;
- } else
+ } else {
nGoodTransactions += block.vtx.size();
+ }
}
if (ShutdownRequested())
return true;
@@ -3627,7 +3659,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
CBlockIndex *pindex = pindexState;
while (pindex != chainActive.Tip()) {
boost::this_thread::interruption_point();
- uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, 100 - (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * 50))));
+ uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, 100 - (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * 50))), false);
pindex = chainActive.Next(pindex);
CBlock block;
if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus()))
@@ -3643,10 +3675,98 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
return true;
}
+/** Apply the effects of a block on the utxo cache, ignoring that it may already have been applied. */
+static bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params)
+{
+ // TODO: merge with ConnectBlock
+ CBlock block;
+ if (!ReadBlockFromDisk(block, pindex, params.GetConsensus())) {
+ return error("ReplayBlock(): ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
+ }
+
+ for (const CTransactionRef& tx : block.vtx) {
+ if (!tx->IsCoinBase()) {
+ for (const CTxIn &txin : tx->vin) {
+ inputs.SpendCoin(txin.prevout);
+ }
+ }
+ // Pass check = true as every addition may be an overwrite.
+ AddCoins(inputs, *tx, pindex->nHeight, true);
+ }
+ return true;
+}
+
+bool ReplayBlocks(const CChainParams& params, CCoinsView* view)
+{
+ LOCK(cs_main);
+
+ CCoinsViewCache cache(view);
+
+ std::vector<uint256> hashHeads = view->GetHeadBlocks();
+ if (hashHeads.empty()) return true; // We're already in a consistent state.
+ if (hashHeads.size() != 2) return error("ReplayBlocks(): unknown inconsistent state");
+
+ uiInterface.ShowProgress(_("Replaying blocks..."), 0, false);
+ LogPrintf("Replaying blocks\n");
+
+ const CBlockIndex* pindexOld = nullptr; // Old tip during the interrupted flush.
+ const CBlockIndex* pindexNew; // New tip during the interrupted flush.
+ const CBlockIndex* pindexFork = nullptr; // Latest block common to both the old and the new tip.
+
+ if (mapBlockIndex.count(hashHeads[0]) == 0) {
+ return error("ReplayBlocks(): reorganization to unknown block requested");
+ }
+ pindexNew = mapBlockIndex[hashHeads[0]];
+
+ if (!hashHeads[1].IsNull()) { // The old tip is allowed to be 0, indicating it's the first flush.
+ if (mapBlockIndex.count(hashHeads[1]) == 0) {
+ return error("ReplayBlocks(): reorganization from unknown block requested");
+ }
+ pindexOld = mapBlockIndex[hashHeads[1]];
+ pindexFork = LastCommonAncestor(pindexOld, pindexNew);
+ assert(pindexFork != nullptr);
+ }
+
+ // Rollback along the old branch.
+ while (pindexOld != pindexFork) {
+ if (pindexOld->nHeight > 0) { // Never disconnect the genesis block.
+ CBlock block;
+ if (!ReadBlockFromDisk(block, pindexOld, params.GetConsensus())) {
+ return error("RollbackBlock(): ReadBlockFromDisk() failed at %d, hash=%s", pindexOld->nHeight, pindexOld->GetBlockHash().ToString());
+ }
+ LogPrintf("Rolling back %s (%i)\n", pindexOld->GetBlockHash().ToString(), pindexOld->nHeight);
+ DisconnectResult res = DisconnectBlock(block, pindexOld, cache);
+ if (res == DISCONNECT_FAILED) {
+ return error("RollbackBlock(): DisconnectBlock failed at %d, hash=%s", pindexOld->nHeight, pindexOld->GetBlockHash().ToString());
+ }
+ // If DISCONNECT_UNCLEAN is returned, it means a non-existing UTXO was deleted, or an existing UTXO was
+ // overwritten. It corresponds to cases where the block-to-be-disconnect never had all its operations
+ // applied to the UTXO set. However, as both writing a UTXO and deleting a UTXO are idempotent operations,
+ // the result is still a version of the UTXO set with the effects of that block undone.
+ }
+ pindexOld = pindexOld->pprev;
+ }
+
+ // Roll forward from the forking point to the new tip.
+ int nForkHeight = pindexFork ? pindexFork->nHeight : 0;
+ for (int nHeight = nForkHeight + 1; nHeight <= pindexNew->nHeight; ++nHeight) {
+ const CBlockIndex* pindex = pindexNew->GetAncestor(nHeight);
+ LogPrintf("Rolling forward %s (%i)\n", pindex->GetBlockHash().ToString(), nHeight);
+ if (!RollforwardBlock(pindex, cache, params)) return false;
+ }
+
+ cache.SetBestBlock(pindexNew->GetBlockHash());
+ cache.Flush();
+ uiInterface.ShowProgress("", 100, false);
+ return true;
+}
+
bool RewindBlockIndex(const CChainParams& params)
{
LOCK(cs_main);
+ // Note that during -reindex-chainstate we are called with an empty chainActive!
+
int nHeight = 1;
while (nHeight <= chainActive.Height()) {
if (IsWitnessEnabled(chainActive[nHeight - 1], params.GetConsensus()) && !(chainActive[nHeight]->nStatus & BLOCK_OPT_WITNESS)) {
@@ -3667,11 +3787,11 @@ bool RewindBlockIndex(const CChainParams& params)
// of the blockchain).
break;
}
- if (!DisconnectTip(state, params, true)) {
+ if (!DisconnectTip(state, params, nullptr)) {
return error("RewindBlockIndex: unable to disconnect block at height %i", pindex->nHeight);
}
// Occasionally flush state to disk.
- if (!FlushStateToDisk(state, FLUSH_STATE_PERIODIC))
+ if (!FlushStateToDisk(params, state, FLUSH_STATE_PERIODIC))
return false;
}
@@ -3716,12 +3836,19 @@ bool RewindBlockIndex(const CChainParams& params)
}
}
- PruneBlockIndexCandidates();
+ if (chainActive.Tip() != nullptr) {
+ // We can't prune block index candidates based on our tip if we have
+ // no tip due to chainActive being empty!
+ PruneBlockIndexCandidates();
- CheckBlockIndex(params.GetConsensus());
+ CheckBlockIndex(params.GetConsensus());
- if (!FlushStateToDisk(state, FLUSH_STATE_ALWAYS)) {
- return false;
+ // FlushStateToDisk can possibly read chainActive. Be conservative
+ // and skip it here, we're about to -reindex-chainstate anyway, so
+ // it'll get called a bunch real soon.
+ if (!FlushStateToDisk(params, state, FLUSH_STATE_ALWAYS)) {
+ return false;
+ }
}
return true;
@@ -3734,9 +3861,9 @@ void UnloadBlockIndex()
{
LOCK(cs_main);
setBlockIndexCandidates.clear();
- chainActive.SetTip(NULL);
- pindexBestInvalid = NULL;
- pindexBestHeader = NULL;
+ chainActive.SetTip(nullptr);
+ pindexBestInvalid = nullptr;
+ pindexBestHeader = nullptr;
mempool.clear();
mapBlocksUnlinked.clear();
vinfoBlockFile.clear();
@@ -3749,7 +3876,7 @@ void UnloadBlockIndex()
warningcache[b].clear();
}
- BOOST_FOREACH(BlockMap::value_type& entry, mapBlockIndex) {
+ for (BlockMap::value_type& entry : mapBlockIndex) {
delete entry.second;
}
mapBlockIndex.clear();
@@ -3759,44 +3886,54 @@ void UnloadBlockIndex()
bool LoadBlockIndex(const CChainParams& chainparams)
{
// Load block index from databases
- if (!fReindex && !LoadBlockIndexDB(chainparams))
- return false;
+ bool needs_init = fReindex;
+ if (!fReindex) {
+ bool ret = LoadBlockIndexDB(chainparams);
+ if (!ret) return false;
+ needs_init = mapBlockIndex.empty();
+ }
+
+ if (needs_init) {
+ // Everything here is for *new* reindex/DBs. Thus, though
+ // LoadBlockIndexDB may have set fReindex if we shut down
+ // mid-reindex previously, we don't check fReindex and
+ // instead only check it prior to LoadBlockIndexDB to set
+ // needs_init.
+
+ LogPrintf("Initializing databases...\n");
+ // Use the provided setting for -txindex in the new database
+ fTxIndex = gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX);
+ pblocktree->WriteFlag("txindex", fTxIndex);
+ }
return true;
}
-bool InitBlockIndex(const CChainParams& chainparams)
+bool LoadGenesisBlock(const CChainParams& chainparams)
{
LOCK(cs_main);
- // Check whether we're already initialized
- if (chainActive.Genesis() != NULL)
+ // Check whether we're already initialized by checking for genesis in
+ // mapBlockIndex. Note that we can't use chainActive here, since it is
+ // set based on the coins db, not the block index db, which is the only
+ // thing loaded at this point.
+ if (mapBlockIndex.count(chainparams.GenesisBlock().GetHash()))
return true;
- // Use the provided setting for -txindex in the new database
- fTxIndex = GetBoolArg("-txindex", DEFAULT_TXINDEX);
- pblocktree->WriteFlag("txindex", fTxIndex);
- LogPrintf("Initializing databases...\n");
-
- // Only add the genesis block if not reindexing (in which case we reuse the one already on disk)
- if (!fReindex) {
- try {
- CBlock &block = const_cast<CBlock&>(chainparams.GenesisBlock());
- // Start new block file
- unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
- CDiskBlockPos blockPos;
- CValidationState state;
- if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.GetBlockTime()))
- return error("LoadBlockIndex(): FindBlockPos failed");
- 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))
- return error("LoadBlockIndex(): genesis block not accepted");
- // Force a chainstate write so that when we VerifyDB in a moment, it doesn't check stale data
- return FlushStateToDisk(state, FLUSH_STATE_ALWAYS);
- } catch (const std::runtime_error& e) {
- return error("LoadBlockIndex(): failed to initialize block database: %s", e.what());
- }
+ try {
+ CBlock &block = const_cast<CBlock&>(chainparams.GenesisBlock());
+ // Start new block file
+ unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
+ CDiskBlockPos blockPos;
+ CValidationState state;
+ if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.GetBlockTime()))
+ return error("%s: FindBlockPos failed", __func__);
+ if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart()))
+ return error("%s: writing genesis block to disk failed", __func__);
+ CBlockIndex *pindex = AddToBlockIndex(block);
+ if (!ReceivedBlockTransactions(block, state, pindex, blockPos, chainparams.GetConsensus()))
+ return error("%s: genesis block not accepted", __func__);
+ } catch (const std::runtime_error& e) {
+ return error("%s: failed to write genesis block: %s", __func__, e.what());
}
return true;
@@ -3851,7 +3988,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
// detect out of order blocks, and store them for later
uint256 hash = block.GetHash();
if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex.find(block.hashPrevBlock) == mapBlockIndex.end()) {
- LogPrint("reindex", "%s: Out of order block %s, parent %s not known\n", __func__, hash.ToString(),
+ LogPrint(BCLog::REINDEX, "%s: Out of order block %s, parent %s not known\n", __func__, hash.ToString(),
block.hashPrevBlock.ToString());
if (dbp)
mapBlocksUnknownParent.insert(std::make_pair(block.hashPrevBlock, *dbp));
@@ -3862,12 +3999,12 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) {
LOCK(cs_main);
CValidationState state;
- if (AcceptBlock(pblock, state, chainparams, NULL, true, dbp, NULL))
+ if (AcceptBlock(pblock, state, chainparams, nullptr, true, dbp, nullptr))
nLoaded++;
if (state.IsError())
break;
} else if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex[hash]->nHeight % 1000 == 0) {
- LogPrint("reindex", "Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->nHeight);
+ LogPrint(BCLog::REINDEX, "Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->nHeight);
}
// Activate the genesis block so normal node progress can continue
@@ -3881,7 +4018,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
NotifyHeaderTip();
// Recursively process earlier encountered successors of this block
- deque<uint256> queue;
+ std::deque<uint256> queue;
queue.push_back(hash);
while (!queue.empty()) {
uint256 head = queue.front();
@@ -3892,11 +4029,11 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
std::shared_ptr<CBlock> pblockrecursive = std::make_shared<CBlock>();
if (ReadBlockFromDisk(*pblockrecursive, it->second, chainparams.GetConsensus()))
{
- LogPrint("reindex", "%s: Processing out of order child %s of %s\n", __func__, pblockrecursive->GetHash().ToString(),
+ LogPrint(BCLog::REINDEX, "%s: Processing out of order child %s of %s\n", __func__, pblockrecursive->GetHash().ToString(),
head.ToString());
LOCK(cs_main);
CValidationState dummy;
- if (AcceptBlock(pblockrecursive, dummy, chainparams, NULL, true, &it->second, NULL))
+ if (AcceptBlock(pblockrecursive, dummy, chainparams, nullptr, true, &it->second, nullptr))
{
nLoaded++;
queue.push_back(pblockrecursive->GetHash());
@@ -3943,35 +4080,35 @@ void static CheckBlockIndex(const Consensus::Params& consensusParams)
assert(forward.size() == mapBlockIndex.size());
- std::pair<std::multimap<CBlockIndex*,CBlockIndex*>::iterator,std::multimap<CBlockIndex*,CBlockIndex*>::iterator> rangeGenesis = forward.equal_range(NULL);
+ std::pair<std::multimap<CBlockIndex*,CBlockIndex*>::iterator,std::multimap<CBlockIndex*,CBlockIndex*>::iterator> rangeGenesis = forward.equal_range(nullptr);
CBlockIndex *pindex = rangeGenesis.first->second;
rangeGenesis.first++;
- assert(rangeGenesis.first == rangeGenesis.second); // There is only one index entry with parent NULL.
+ assert(rangeGenesis.first == rangeGenesis.second); // There is only one index entry with parent nullptr.
// Iterate over the entire block tree, using depth-first search.
// Along the way, remember whether there are blocks on the path from genesis
// block being explored which are the first to have certain properties.
size_t nNodes = 0;
int nHeight = 0;
- CBlockIndex* pindexFirstInvalid = NULL; // Oldest ancestor of pindex which is invalid.
- CBlockIndex* pindexFirstMissing = NULL; // Oldest ancestor of pindex which does not have BLOCK_HAVE_DATA.
- CBlockIndex* pindexFirstNeverProcessed = NULL; // Oldest ancestor of pindex for which nTx == 0.
- CBlockIndex* pindexFirstNotTreeValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_TREE (regardless of being valid or not).
- CBlockIndex* pindexFirstNotTransactionsValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_TRANSACTIONS (regardless of being valid or not).
- CBlockIndex* pindexFirstNotChainValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_CHAIN (regardless of being valid or not).
- CBlockIndex* pindexFirstNotScriptsValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_SCRIPTS (regardless of being valid or not).
- while (pindex != NULL) {
+ CBlockIndex* pindexFirstInvalid = nullptr; // Oldest ancestor of pindex which is invalid.
+ CBlockIndex* pindexFirstMissing = nullptr; // Oldest ancestor of pindex which does not have BLOCK_HAVE_DATA.
+ CBlockIndex* pindexFirstNeverProcessed = nullptr; // Oldest ancestor of pindex for which nTx == 0.
+ CBlockIndex* pindexFirstNotTreeValid = nullptr; // Oldest ancestor of pindex which does not have BLOCK_VALID_TREE (regardless of being valid or not).
+ CBlockIndex* pindexFirstNotTransactionsValid = nullptr; // Oldest ancestor of pindex which does not have BLOCK_VALID_TRANSACTIONS (regardless of being valid or not).
+ CBlockIndex* pindexFirstNotChainValid = nullptr; // Oldest ancestor of pindex which does not have BLOCK_VALID_CHAIN (regardless of being valid or not).
+ CBlockIndex* pindexFirstNotScriptsValid = nullptr; // Oldest ancestor of pindex which does not have BLOCK_VALID_SCRIPTS (regardless of being valid or not).
+ while (pindex != nullptr) {
nNodes++;
- if (pindexFirstInvalid == NULL && pindex->nStatus & BLOCK_FAILED_VALID) pindexFirstInvalid = pindex;
- if (pindexFirstMissing == NULL && !(pindex->nStatus & BLOCK_HAVE_DATA)) pindexFirstMissing = pindex;
- if (pindexFirstNeverProcessed == NULL && pindex->nTx == 0) pindexFirstNeverProcessed = pindex;
- if (pindex->pprev != NULL && pindexFirstNotTreeValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_TREE) pindexFirstNotTreeValid = pindex;
- if (pindex->pprev != NULL && pindexFirstNotTransactionsValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_TRANSACTIONS) pindexFirstNotTransactionsValid = pindex;
- if (pindex->pprev != NULL && pindexFirstNotChainValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_CHAIN) pindexFirstNotChainValid = pindex;
- if (pindex->pprev != NULL && pindexFirstNotScriptsValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_SCRIPTS) pindexFirstNotScriptsValid = pindex;
+ if (pindexFirstInvalid == nullptr && pindex->nStatus & BLOCK_FAILED_VALID) pindexFirstInvalid = pindex;
+ if (pindexFirstMissing == nullptr && !(pindex->nStatus & BLOCK_HAVE_DATA)) pindexFirstMissing = pindex;
+ if (pindexFirstNeverProcessed == nullptr && pindex->nTx == 0) pindexFirstNeverProcessed = pindex;
+ if (pindex->pprev != nullptr && pindexFirstNotTreeValid == nullptr && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_TREE) pindexFirstNotTreeValid = pindex;
+ if (pindex->pprev != nullptr && pindexFirstNotTransactionsValid == nullptr && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_TRANSACTIONS) pindexFirstNotTransactionsValid = pindex;
+ if (pindex->pprev != nullptr && pindexFirstNotChainValid == nullptr && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_CHAIN) pindexFirstNotChainValid = pindex;
+ if (pindex->pprev != nullptr && pindexFirstNotScriptsValid == nullptr && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_SCRIPTS) pindexFirstNotScriptsValid = pindex;
// Begin: actual consistency checks.
- if (pindex->pprev == NULL) {
+ if (pindex->pprev == nullptr) {
// Genesis block checks.
assert(pindex->GetBlockHash() == consensusParams.hashGenesisBlock); // Genesis block's hash must match.
assert(pindex == chainActive.Genesis()); // The current active chain's genesis block must be this block.
@@ -3990,26 +4127,26 @@ void static CheckBlockIndex(const Consensus::Params& consensusParams)
if (pindex->nStatus & BLOCK_HAVE_UNDO) assert(pindex->nStatus & BLOCK_HAVE_DATA);
assert(((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TRANSACTIONS) == (pindex->nTx > 0)); // This is pruning-independent.
// All parents having had data (at some point) is equivalent to all parents being VALID_TRANSACTIONS, which is equivalent to nChainTx being set.
- assert((pindexFirstNeverProcessed != NULL) == (pindex->nChainTx == 0)); // nChainTx != 0 is used to signal that all parent blocks have been processed (but may have been pruned).
- assert((pindexFirstNotTransactionsValid != NULL) == (pindex->nChainTx == 0));
+ assert((pindexFirstNeverProcessed != nullptr) == (pindex->nChainTx == 0)); // nChainTx != 0 is used to signal that all parent blocks have been processed (but may have been pruned).
+ assert((pindexFirstNotTransactionsValid != nullptr) == (pindex->nChainTx == 0));
assert(pindex->nHeight == nHeight); // nHeight must be consistent.
- assert(pindex->pprev == NULL || pindex->nChainWork >= pindex->pprev->nChainWork); // For every block except the genesis block, the chainwork must be larger than the parent's.
+ assert(pindex->pprev == nullptr || pindex->nChainWork >= pindex->pprev->nChainWork); // For every block except the genesis block, the chainwork must be larger than the parent's.
assert(nHeight < 2 || (pindex->pskip && (pindex->pskip->nHeight < nHeight))); // The pskip pointer must point back for all but the first 2 blocks.
- assert(pindexFirstNotTreeValid == NULL); // All mapBlockIndex entries must at least be TREE valid
- if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TREE) assert(pindexFirstNotTreeValid == NULL); // TREE valid implies all parents are TREE valid
- if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_CHAIN) assert(pindexFirstNotChainValid == NULL); // CHAIN valid implies all parents are CHAIN valid
- if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_SCRIPTS) assert(pindexFirstNotScriptsValid == NULL); // SCRIPTS valid implies all parents are SCRIPTS valid
- if (pindexFirstInvalid == NULL) {
+ assert(pindexFirstNotTreeValid == nullptr); // All mapBlockIndex entries must at least be TREE valid
+ if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TREE) assert(pindexFirstNotTreeValid == nullptr); // TREE valid implies all parents are TREE valid
+ if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_CHAIN) assert(pindexFirstNotChainValid == nullptr); // CHAIN valid implies all parents are CHAIN valid
+ if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_SCRIPTS) assert(pindexFirstNotScriptsValid == nullptr); // SCRIPTS valid implies all parents are SCRIPTS valid
+ if (pindexFirstInvalid == nullptr) {
// Checks for not-invalid blocks.
assert((pindex->nStatus & BLOCK_FAILED_MASK) == 0); // The failed mask cannot be set for blocks without invalid parents.
}
- if (!CBlockIndexWorkComparator()(pindex, chainActive.Tip()) && pindexFirstNeverProcessed == NULL) {
- if (pindexFirstInvalid == NULL) {
+ if (!CBlockIndexWorkComparator()(pindex, chainActive.Tip()) && pindexFirstNeverProcessed == nullptr) {
+ if (pindexFirstInvalid == nullptr) {
// If this block sorts at least as good as the current tip and
// is valid and we have all data for its parents, it must be in
// setBlockIndexCandidates. chainActive.Tip() must also be there
// even if some data has been pruned.
- if (pindexFirstMissing == NULL || pindex == chainActive.Tip()) {
+ if (pindexFirstMissing == nullptr || pindex == chainActive.Tip()) {
assert(setBlockIndexCandidates.count(pindex));
}
// If some parent is missing, then it could be that this block was in
@@ -4030,13 +4167,13 @@ void static CheckBlockIndex(const Consensus::Params& consensusParams)
}
rangeUnlinked.first++;
}
- if (pindex->pprev && (pindex->nStatus & BLOCK_HAVE_DATA) && pindexFirstNeverProcessed != NULL && pindexFirstInvalid == NULL) {
+ if (pindex->pprev && (pindex->nStatus & BLOCK_HAVE_DATA) && pindexFirstNeverProcessed != nullptr && pindexFirstInvalid == nullptr) {
// If this block has block data available, some parent was never received, and has no invalid parents, it must be in mapBlocksUnlinked.
assert(foundInUnlinked);
}
if (!(pindex->nStatus & BLOCK_HAVE_DATA)) assert(!foundInUnlinked); // Can't be in mapBlocksUnlinked if we don't HAVE_DATA
- if (pindexFirstMissing == NULL) assert(!foundInUnlinked); // We aren't missing data for any parent -- cannot be in mapBlocksUnlinked.
- if (pindex->pprev && (pindex->nStatus & BLOCK_HAVE_DATA) && pindexFirstNeverProcessed == NULL && pindexFirstMissing != NULL) {
+ if (pindexFirstMissing == nullptr) assert(!foundInUnlinked); // We aren't missing data for any parent -- cannot be in mapBlocksUnlinked.
+ if (pindex->pprev && (pindex->nStatus & BLOCK_HAVE_DATA) && pindexFirstNeverProcessed == nullptr && pindexFirstMissing != nullptr) {
// We HAVE_DATA for this block, have received data for all parents at some point, but we're currently missing data for some parent.
assert(fHavePruned); // We must have pruned.
// This block may have entered mapBlocksUnlinked if:
@@ -4048,7 +4185,7 @@ void static CheckBlockIndex(const Consensus::Params& consensusParams)
// So if this block is itself better than chainActive.Tip() and it wasn't in
// setBlockIndexCandidates, then it must be in mapBlocksUnlinked.
if (!CBlockIndexWorkComparator()(pindex, chainActive.Tip()) && setBlockIndexCandidates.count(pindex) == 0) {
- if (pindexFirstInvalid == NULL) {
+ if (pindexFirstInvalid == nullptr) {
assert(foundInUnlinked);
}
}
@@ -4069,13 +4206,13 @@ void static CheckBlockIndex(const Consensus::Params& consensusParams)
while (pindex) {
// We are going to either move to a parent or a sibling of pindex.
// If pindex was the first with a certain property, unset the corresponding variable.
- if (pindex == pindexFirstInvalid) pindexFirstInvalid = NULL;
- if (pindex == pindexFirstMissing) pindexFirstMissing = NULL;
- if (pindex == pindexFirstNeverProcessed) pindexFirstNeverProcessed = NULL;
- if (pindex == pindexFirstNotTreeValid) pindexFirstNotTreeValid = NULL;
- if (pindex == pindexFirstNotTransactionsValid) pindexFirstNotTransactionsValid = NULL;
- if (pindex == pindexFirstNotChainValid) pindexFirstNotChainValid = NULL;
- if (pindex == pindexFirstNotScriptsValid) pindexFirstNotScriptsValid = NULL;
+ if (pindex == pindexFirstInvalid) pindexFirstInvalid = nullptr;
+ if (pindex == pindexFirstMissing) pindexFirstMissing = nullptr;
+ if (pindex == pindexFirstNeverProcessed) pindexFirstNeverProcessed = nullptr;
+ if (pindex == pindexFirstNotTreeValid) pindexFirstNotTreeValid = nullptr;
+ if (pindex == pindexFirstNotTransactionsValid) pindexFirstNotTransactionsValid = nullptr;
+ if (pindex == pindexFirstNotChainValid) pindexFirstNotChainValid = nullptr;
+ if (pindex == pindexFirstNotScriptsValid) pindexFirstNotScriptsValid = nullptr;
// Find our parent.
CBlockIndex* pindexPar = pindex->pprev;
// Find which child we just visited.
@@ -4108,12 +4245,23 @@ std::string CBlockFileInfo::ToString() const
return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst), DateTimeStrFormat("%Y-%m-%d", nTimeLast));
}
+CBlockFileInfo* GetBlockFileInfo(size_t n)
+{
+ return &vinfoBlockFile.at(n);
+}
+
ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos)
{
LOCK(cs_main);
return VersionBitsState(chainActive.Tip(), params, pos, versionbitscache);
}
+BIP9Stats VersionBitsTipStatistics(const Consensus::Params& params, Consensus::DeploymentPos pos)
+{
+ LOCK(cs_main);
+ return VersionBitsStatistics(chainActive.Tip(), params, pos);
+}
+
int VersionBitsTipStateSinceHeight(const Consensus::Params& params, Consensus::DeploymentPos pos)
{
LOCK(cs_main);
@@ -4124,8 +4272,9 @@ static const uint64_t MEMPOOL_DUMP_VERSION = 1;
bool LoadMempool(void)
{
- int64_t nExpiryTimeout = GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60;
- FILE* filestr = fopen((GetDataDir() / "mempool.dat").string().c_str(), "r");
+ const CChainParams& chainparams = Params();
+ int64_t nExpiryTimeout = gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60;
+ FILE* filestr = fsbridge::fopen(GetDataDir() / "mempool.dat", "rb");
CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
if (file.IsNull()) {
LogPrintf("Failed to open mempool file from disk. Continuing anyway.\n");
@@ -4145,7 +4294,6 @@ bool LoadMempool(void)
}
uint64_t num;
file >> num;
- double prioritydummy = 0;
while (num--) {
CTransactionRef tx;
int64_t nTime;
@@ -4156,12 +4304,13 @@ bool LoadMempool(void)
CAmount amountdelta = nFeeDelta;
if (amountdelta) {
- mempool.PrioritiseTransaction(tx->GetHash(), tx->GetHash().ToString(), prioritydummy, amountdelta);
+ mempool.PrioritiseTransaction(tx->GetHash(), amountdelta);
}
CValidationState state;
if (nTime + nExpiryTimeout > nNow) {
LOCK(cs_main);
- AcceptToMemoryPoolWithTime(mempool, state, tx, true, NULL, nTime);
+ AcceptToMemoryPoolWithTime(chainparams, mempool, state, tx, nullptr /* pfMissingInputs */, nTime,
+ nullptr /* plTxnReplaced */, false /* bypass_limits */, 0 /* nAbsurdFee */);
if (state.IsValid()) {
++count;
} else {
@@ -4177,7 +4326,7 @@ bool LoadMempool(void)
file >> mapDeltas;
for (const auto& i : mapDeltas) {
- mempool.PrioritiseTransaction(i.first, i.first.ToString(), prioritydummy, i.second);
+ mempool.PrioritiseTransaction(i.first, i.second);
}
} catch (const std::exception& e) {
LogPrintf("Failed to deserialize mempool data on disk: %s. Continuing anyway.\n", e.what());
@@ -4188,7 +4337,7 @@ bool LoadMempool(void)
return true;
}
-void DumpMempool(void)
+bool DumpMempool(void)
{
int64_t start = GetTimeMicros();
@@ -4198,7 +4347,7 @@ void DumpMempool(void)
{
LOCK(mempool.cs);
for (const auto &i : mempool.mapDeltas) {
- mapDeltas[i.first] = i.second.first;
+ mapDeltas[i.first] = i.second;
}
vinfo = mempool.infoAll();
}
@@ -4206,9 +4355,9 @@ void DumpMempool(void)
int64_t mid = GetTimeMicros();
try {
- FILE* filestr = fopen((GetDataDir() / "mempool.dat.new").string().c_str(), "w");
+ FILE* filestr = fsbridge::fopen(GetDataDir() / "mempool.dat.new", "wb");
if (!filestr) {
- return;
+ return false;
}
CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
@@ -4229,18 +4378,20 @@ void DumpMempool(void)
file.fclose();
RenameOver(GetDataDir() / "mempool.dat.new", GetDataDir() / "mempool.dat");
int64_t last = GetTimeMicros();
- LogPrintf("Dumped mempool: %gs to copy, %gs to dump\n", (mid-start)*0.000001, (last-mid)*0.000001);
+ LogPrintf("Dumped mempool: %gs to copy, %gs to dump\n", (mid-start)*MICRO, (last-mid)*MICRO);
} catch (const std::exception& e) {
LogPrintf("Failed to dump mempool: %s. Continuing anyway.\n", e.what());
+ return false;
}
+ return true;
}
//! Guess how far we are in the verification process at the given block index
double GuessVerificationProgress(const ChainTxData& data, CBlockIndex *pindex) {
- if (pindex == NULL)
+ if (pindex == nullptr)
return 0.0;
- int64_t nNow = time(NULL);
+ int64_t nNow = time(nullptr);
double fTxTotal;
diff --git a/src/validation.h b/src/validation.h
index e57c636422..50974ac989 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -11,9 +11,10 @@
#endif
#include "amount.h"
-#include "chain.h"
#include "coins.h"
+#include "fs.h"
#include "protocol.h" // For CMessageHeader::MessageStartChars
+#include "policy/feerate.h"
#include "script/script_error.h"
#include "sync.h"
#include "versionbits.h"
@@ -29,27 +30,24 @@
#include <atomic>
-#include <boost/unordered_map.hpp>
-#include <boost/filesystem/path.hpp>
-
class CBlockIndex;
class CBlockTreeDB;
-class CBloomFilter;
class CChainParams;
+class CCoinsViewDB;
class CInv;
class CConnman;
class CScriptCheck;
+class CBlockPolicyEstimator;
class CTxMemPool;
-class CValidationInterface;
class CValidationState;
struct ChainTxData;
struct PrecomputedTransactionData;
struct LockPoints;
-/** Default for DEFAULT_WHITELISTRELAY. */
+/** Default for -whitelistrelay. */
static const bool DEFAULT_WHITELISTRELAY = true;
-/** Default for DEFAULT_WHITELISTFORCERELAY. */
+/** Default for -whitelistforcerelay. */
static const bool DEFAULT_WHITELISTFORCERELAY = true;
/** Default for -minrelaytxfee, minimum relay fee for transactions */
static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 1000;
@@ -59,12 +57,6 @@ static const CAmount DEFAULT_TRANSACTION_MAXFEE = 0.1 * COIN;
static const CAmount HIGH_TX_FEE_PER_KB = 0.01 * COIN;
//! -maxtxfee will warn if called with a higher fee than this amount (in satoshis)
static const CAmount HIGH_MAX_TX_FEE = 100 * HIGH_TX_FEE_PER_KB;
-/** Default for -maxorphantx, maximum number of orphan transactions kept in memory */
-static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100;
-/** Expiration time for orphan transactions in seconds */
-static const int64_t ORPHAN_TX_EXPIRE_TIME = 20 * 60;
-/** Minimum time between orphan transactions expire time checks in seconds */
-static const int64_t ORPHAN_TX_EXPIRE_INTERVAL = 5 * 60;
/** Default for -limitancestorcount, max number of in-mempool ancestors */
static const unsigned int DEFAULT_ANCESTOR_LIMIT = 25;
/** Default for -limitancestorsize, maximum kilobytes of tx + all in-mempool ancestors */
@@ -75,6 +67,8 @@ static const unsigned int DEFAULT_DESCENDANT_LIMIT = 25;
static const unsigned int DEFAULT_DESCENDANT_SIZE_LIMIT = 101;
/** Default for -mempoolexpiry, expiration time for mempool transactions in hours */
static const unsigned int DEFAULT_MEMPOOL_EXPIRY = 336;
+/** Maximum kilobytes for transactions to store for processing during reorg */
+static const unsigned int MAX_DISCONNECTED_TX_POOL_SIZE = 20000;
/** 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) */
@@ -100,8 +94,8 @@ static const int MAX_CMPCTBLOCK_DEPTH = 5;
static const int MAX_BLOCKTXN_DEPTH = 10;
/** Size of the "block download window": how far ahead of our current height do we fetch?
* Larger windows tolerate larger download speed differences between peer, but increase the potential
- * 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. */
+ * degree of disordering of blocks on disk (which make reindexing and 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 blocks/block index to disk. */
static const unsigned int DATABASE_WRITE_INTERVAL = 60 * 60;
@@ -110,7 +104,7 @@ static const unsigned int DATABASE_FLUSH_INTERVAL = 24 * 60 * 60;
/** Maximum length of reject messages. */
static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111;
/** Average delay between local address broadcasts in seconds. */
-static const unsigned int AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL = 24 * 24 * 60;
+static const unsigned int AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL = 24 * 60 * 60;
/** Average delay between peer address broadcasts in seconds. */
static const unsigned int AVG_ADDRESS_BROADCAST_INTERVAL = 30;
/** Average delay between trickled inventory transmissions in seconds.
@@ -128,8 +122,6 @@ static const int64_t BLOCK_DOWNLOAD_TIMEOUT_BASE = 1000000;
/** Additional block download timeout per parallel downloading peer (i.e. 5 min) */
static const int64_t BLOCK_DOWNLOAD_TIMEOUT_PER_PEER = 500000;
-static const unsigned int DEFAULT_LIMITFREERELAY = 0;
-static const bool DEFAULT_RELAYPRIORITY = true;
static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60;
/** Maximum age of our tip in seconds for us to be considered current for fee estimation */
static const int64_t MAX_FEE_ESTIMATION_TIP_AGE = 3 * 60 * 60;
@@ -139,7 +131,8 @@ static const bool DEFAULT_PERMIT_BAREMULTISIG = true;
static const bool DEFAULT_CHECKPOINTS_ENABLED = true;
static const bool DEFAULT_TXINDEX = false;
static const unsigned int DEFAULT_BANSCORE_THRESHOLD = 100;
-
+/** Default for -persistmempool */
+static const bool DEFAULT_PERSIST_MEMPOOL = true;
/** Default for -mempoolreplacement */
static const bool DEFAULT_ENABLE_REPLACEMENT = true;
/** Default for using fee filter */
@@ -153,6 +146,9 @@ static const int MAX_UNCONNECTING_HEADERS = 10;
static const bool DEFAULT_PEERBLOOMFILTERS = true;
+/** Default for -stopatheight */
+static const int DEFAULT_STOPATHEIGHT = 0;
+
struct BlockHasher
{
size_t operator()(const uint256& hash) const { return hash.GetCheapHash(); }
@@ -160,17 +156,17 @@ struct BlockHasher
extern CScript COINBASE_FLAGS;
extern CCriticalSection cs_main;
+extern CBlockPolicyEstimator feeEstimator;
extern CTxMemPool mempool;
-typedef boost::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap;
+typedef std::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap;
extern BlockMap mapBlockIndex;
extern uint64_t nLastBlockTx;
-extern uint64_t nLastBlockSize;
extern uint64_t nLastBlockWeight;
extern const std::string strMessageMagic;
extern CWaitableCriticalSection csBestBlock;
extern CConditionVariable cvBlockChange;
extern std::atomic_bool fImporting;
-extern bool fReindex;
+extern std::atomic_bool fReindex;
extern int nScriptCheckThreads;
extern bool fTxIndex;
extern bool fIsBareMultisigStd;
@@ -189,6 +185,9 @@ extern bool fEnableReplacement;
/** Block hash whose ancestors we will assume to have valid scripts without checking them. */
extern uint256 hashAssumeValid;
+/** Minimum work we will assume exists on some valid chain. */
+extern arith_uint256 nMinimumChainWork;
+
/** Best header we've seen so far (used for getheaders queries' starting points). */
extern CBlockIndex *pindexBestHeader;
@@ -249,36 +248,29 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
* @param[in] chainparams The params for the chain we want to connect to
* @param[out] ppindex If set, the pointer will be set to point to the last new block index object for the given headers
*/
-bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex=NULL);
+bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex=nullptr);
/** Check whether enough disk space is available for an incoming block */
bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);
/** Open a block file (blk?????.dat) */
FILE* OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly = false);
-/** Open an undo file (rev?????.dat) */
-FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly = false);
/** Translation to a filesystem path */
-boost::filesystem::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix);
+fs::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix);
/** Import blocks from an external file */
-bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskBlockPos *dbp = NULL);
-/** Initialize a new block tree database + block data on disk */
-bool InitBlockIndex(const CChainParams& chainparams);
-/** Load the block tree and coins database from disk */
+bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskBlockPos *dbp = nullptr);
+/** Ensures we have a genesis block in the block tree, possibly writing one to disk. */
+bool LoadGenesisBlock(const CChainParams& chainparams);
+/** Load the block tree and coins database from disk,
+ * initializing state if we're running with -reindex. */
bool LoadBlockIndex(const CChainParams& chainparams);
+/** Update the chain tip based on database information. */
+bool LoadChainTip(const CChainParams& chainparams);
/** Unload database information */
void UnloadBlockIndex();
/** Run an instance of the script checking thread */
void ThreadScriptCheck();
/** 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.
- * strFor can have three values:
- * - "rpc": get critical warnings, which should put the client in safe mode if non-empty
- * - "statusbar": get all warnings
- * - "gui": get all warnings, translated (where possible) for GUI
- * This function only returns the highest priority warning of the set selected by strFor.
- */
-std::string GetWarnings(const std::string& strFor);
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
bool GetTransaction(const uint256 &hash, CTransactionRef &tx, const Consensus::Params& params, uint256 &hashBlock, bool fAllowSlow = false);
/** Find the best known block, and make it the tip of the block chain */
@@ -289,26 +281,14 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);
double GuessVerificationProgress(const ChainTxData& data, CBlockIndex* pindex);
/**
- * Prune block and undo files (blk???.dat and undo???.dat) so that the disk space used is less than a user-defined target.
- * The user sets the target (in MB) on the command line or in config file. This will be run on startup and whenever new
- * space is allocated in a block or undo file, staying below the target. Changing back to unpruned requires a reindex
- * (which in this case means the blockchain must be re-downloaded.)
- *
- * Pruning functions are called from FlushStateToDisk when the global fCheckForPruning flag has been set.
- * Block and undo files are deleted in lock-step (when blk00003.dat is deleted, so is rev00003.dat.)
- * Pruning cannot take place until the longest chain is at least a certain length (100000 on mainnet, 1000 on testnet, 1000 on regtest).
- * Pruning will never delete a block within a defined distance (currently 288) from the active chain's tip.
- * The block index is updated by unsetting HAVE_DATA and HAVE_UNDO for any blocks that were stored in the deleted files.
- * A db flag records the fact that at least some block files have been pruned.
- *
- * @param[out] setFilesToPrune The set of file indices that can be unlinked will be returned
+ * Mark one block file as pruned.
*/
-void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight);
+void PruneOneBlockFile(const int fileNumber);
/**
* Actually unlink the specified files
*/
-void UnlinkPrunedFiles(std::set<int>& setFilesToPrune);
+void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune);
/** Create a new block index entry for a given block hash */
CBlockIndex * InsertBlockIndex(uint256 hash);
@@ -317,15 +297,13 @@ void FlushStateToDisk();
/** Prune block files and flush state to disk. */
void PruneAndFlush();
/** Prune block files up to a given height */
-void PruneBlockFilesManual(int nPruneUpToHeight);
-
-/** (try to) add transaction to memory pool **/
-bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, bool fLimitFree,
- bool* pfMissingInputs, bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0);
+void PruneBlockFilesManual(int nManualPruneHeight);
-/** (try to) add transaction to memory pool with a specified acceptance time **/
-bool AcceptToMemoryPoolWithTime(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, bool fLimitFree,
- bool* pfMissingInputs, int64_t nAcceptTime, bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0);
+/** (try to) add transaction to memory pool
+ * plTxnReplaced will be appended to with all transactions replaced from mempool **/
+bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx,
+ bool* pfMissingInputs, std::list<CTransactionRef>* plTxnReplaced,
+ bool bypass_limits, const CAmount nAbsurdFee);
/** Convert CValidationState to a human-readable message for logging */
std::string FormatStateMessage(const CValidationState &state);
@@ -333,67 +311,18 @@ std::string FormatStateMessage(const CValidationState &state);
/** Get the BIP9 state for a given deployment at the current tip. */
ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos);
+/** Get the numerical statistics for the BIP9 state for a given deployment at the current tip. */
+BIP9Stats VersionBitsTipStatistics(const Consensus::Params& params, Consensus::DeploymentPos pos);
+
/** Get the block height at which the BIP9 deployment switched into the state for the block building on the current tip. */
int VersionBitsTipStateSinceHeight(const Consensus::Params& params, Consensus::DeploymentPos pos);
-/**
- * Count ECDSA signature operations the old-fashioned (pre-0.6) way
- * @return number of sigops this transaction's outputs will produce when spent
- * @see CTransaction::FetchInputs
- */
-unsigned int GetLegacySigOpCount(const CTransaction& tx);
-
-/**
- * Count ECDSA signature operations in pay-to-script-hash inputs.
- *
- * @param[in] mapInputs Map of previous transactions that have outputs we're spending
- * @return maximum number of sigops required to validate this transaction's inputs
- * @see CTransaction::FetchInputs
- */
-unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& mapInputs);
-
-/**
- * Compute total signature operation cost of a transaction.
- * @param[in] tx Transaction for which we are computing the cost
- * @param[in] inputs Map of previous transactions that have outputs we're spending
- * @param[out] flags Script verification flags
- * @return Total signature operation cost of tx
- */
-int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, int flags);
-
-/**
- * Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
- * This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it
- * instead of being performed inline.
- */
-bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks,
- unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks = NULL);
/** Apply the effects of this transaction on the UTXO set represented by view */
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight);
/** Transaction validation functions */
-/** Context-independent validity checks */
-bool CheckTransaction(const CTransaction& tx, CValidationState& state, bool fCheckDuplicateInputs=true);
-
-namespace Consensus {
-
-/**
- * Check whether all inputs of this transaction are valid (no double spends and amounts)
- * This does not modify the UTXO set. This does not check scripts and sigs.
- * Preconditions: tx.IsCoinBase() is false.
- */
-bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight);
-
-} // namespace Consensus
-
-/**
- * Check if transaction is final and can be included in a block with the
- * specified height and time. Consensus critical.
- */
-bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime);
-
/**
* Check if transaction will be final in the next block to be created.
*
@@ -409,12 +338,6 @@ bool CheckFinalTx(const CTransaction &tx, int flags = -1);
bool TestLockPointValidity(const LockPoints* lp);
/**
- * Check if transaction is final per BIP 68 sequence numbers and can be included in a block.
- * Consensus critical. Takes as input a list of heights at which tx's inputs (in order) confirmed.
- */
-bool SequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeights, const CBlockIndex& block);
-
-/**
* Check if transaction will be BIP 68 final in the next block to be created.
*
* Simulates calling SequenceLocks() with data from the tip of the current active chain.
@@ -425,7 +348,7 @@ bool SequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeig
*
* See consensus/consensus.h for flag definitions.
*/
-bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp = NULL, bool useExistingLockPoints = false);
+bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp = nullptr, bool useExistingLockPoints = false);
/**
* Closure representing one script verification
@@ -434,8 +357,7 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp = NULL
class CScriptCheck
{
private:
- CScript scriptPubKey;
- CAmount amount;
+ CTxOut m_tx_out;
const CTransaction *ptxTo;
unsigned int nIn;
unsigned int nFlags;
@@ -444,17 +366,15 @@ private:
PrecomputedTransactionData *txdata;
public:
- CScriptCheck(): amount(0), ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {}
- CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) :
- scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), amount(txFromIn.vout[txToIn.vin[nInIn].prevout.n].nValue),
- ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR), txdata(txdataIn) { }
+ CScriptCheck(): ptxTo(nullptr), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {}
+ CScriptCheck(const CTxOut& outIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) :
+ m_tx_out(outIn), ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR), txdata(txdataIn) { }
bool operator()();
void swap(CScriptCheck &check) {
- scriptPubKey.swap(check.scriptPubKey);
std::swap(ptxTo, check.ptxTo);
- std::swap(amount, check.amount);
+ std::swap(m_tx_out, check.m_tx_out);
std::swap(nIn, check.nIn);
std::swap(nFlags, check.nFlags);
std::swap(cacheStore, check.cacheStore);
@@ -465,36 +385,19 @@ public:
ScriptError GetScriptError() const { return error; }
};
+/** Initializes the script-execution cache */
+void InitScriptExecutionCache();
+
/** Functions for disk access for blocks */
-bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart);
bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus::Params& consensusParams);
bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams);
/** Functions for validating blocks and updating the block tree */
/** Context-independent validity checks */
-bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true);
bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
-/** Context-dependent validity checks.
- * By "context", we mean only the previous block headers, but not the UTXO
- * set; UTXO-related validity checks are done in ConnectBlock(). */
-bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev, int64_t nAdjustedTime);
-bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev);
-
-/** Apply the effects of this block (with given index) on the UTXO set represented by coins.
- * Validity checks that depend on the UTXO set are also done; ConnectBlock()
- * can fail if those validity checks fail (among other reasons). */
-bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins,
- const CChainParams& chainparams, bool fJustCheck = false);
-
-/** Undo the effects of this block (with given index) on the UTXO set represented by coins.
- * 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(const CBlock& block, CValidationState& state, const CBlockIndex* pindex, CCoinsViewCache& coins, bool* pfClean = NULL);
-
/** 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 CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
@@ -518,6 +421,9 @@ public:
bool VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, int nCheckLevel, int nCheckDepth);
};
+/** Replay blocks that aren't fully applied to the database. */
+bool ReplayBlocks(const CChainParams& params, CCoinsView* view);
+
/** Find the last common block between the parameter chain and a locator. */
CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator);
@@ -533,6 +439,9 @@ bool ResetBlockFailureFlags(CBlockIndex *pindex);
/** The currently-connected chain of blocks (protected by cs_main). */
extern CChain chainActive;
+/** Global variable that points to the coins database (protected by cs_main) */
+extern CCoinsViewDB *pcoinsdbview;
+
/** Global variable that points to the active CCoinsView (protected by cs_main) */
extern CCoinsViewCache *pcoinsTip;
@@ -560,13 +469,12 @@ int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Para
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;
+
+/** Get block file info entry for one block file */
+CBlockFileInfo* GetBlockFileInfo(size_t n);
/** Dump the mempool to disk. */
-void DumpMempool();
+bool DumpMempool();
/** Load the mempool from disk. */
bool LoadMempool();
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
index d4121a28bc..281bc04b0a 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -5,48 +5,124 @@
#include "validationinterface.h"
+#include "init.h"
+#include "primitives/block.h"
+#include "scheduler.h"
+#include "sync.h"
+#include "util.h"
+
+#include <list>
+#include <atomic>
+
+#include <boost/signals2/signal.hpp>
+
+struct MainSignalsInstance {
+ boost::signals2::signal<void (const CBlockIndex *, const CBlockIndex *, bool fInitialDownload)> UpdatedBlockTip;
+ boost::signals2::signal<void (const CTransactionRef &)> TransactionAddedToMempool;
+ boost::signals2::signal<void (const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::vector<CTransactionRef>&)> BlockConnected;
+ boost::signals2::signal<void (const std::shared_ptr<const CBlock> &)> BlockDisconnected;
+ boost::signals2::signal<void (const CBlockLocator &)> SetBestChain;
+ boost::signals2::signal<void (const uint256 &)> Inventory;
+ boost::signals2::signal<void (int64_t nBestBlockTime, CConnman* connman)> Broadcast;
+ boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked;
+ boost::signals2::signal<void (const CBlockIndex *, const std::shared_ptr<const CBlock>&)> NewPoWValidBlock;
+
+ // We are not allowed to assume the scheduler only runs in one thread,
+ // but must ensure all callbacks happen in-order, so we end up creating
+ // our own queue here :(
+ SingleThreadedSchedulerClient m_schedulerClient;
+
+ explicit MainSignalsInstance(CScheduler *pscheduler) : m_schedulerClient(pscheduler) {}
+};
+
static CMainSignals g_signals;
+void CMainSignals::RegisterBackgroundSignalScheduler(CScheduler& scheduler) {
+ assert(!m_internals);
+ m_internals.reset(new MainSignalsInstance(&scheduler));
+}
+
+void CMainSignals::UnregisterBackgroundSignalScheduler() {
+ m_internals.reset(nullptr);
+}
+
+void CMainSignals::FlushBackgroundCallbacks() {
+ m_internals->m_schedulerClient.EmptyQueue();
+}
+
CMainSignals& GetMainSignals()
{
return g_signals;
}
void RegisterValidationInterface(CValidationInterface* pwalletIn) {
- g_signals.UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));
- g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2, _3));
- 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, _2));
- 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));
- g_signals.NewPoWValidBlock.connect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
+ g_signals.m_internals->UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));
+ g_signals.m_internals->TransactionAddedToMempool.connect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1));
+ g_signals.m_internals->BlockConnected.connect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
+ g_signals.m_internals->BlockDisconnected.connect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));
+ g_signals.m_internals->SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
+ g_signals.m_internals->Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
+ g_signals.m_internals->Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
+ g_signals.m_internals->BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
+ g_signals.m_internals->NewPoWValidBlock.connect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
}
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, _2));
- 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.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2, _3));
- g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));
- g_signals.NewPoWValidBlock.disconnect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
+ g_signals.m_internals->BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
+ g_signals.m_internals->Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
+ g_signals.m_internals->Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
+ g_signals.m_internals->SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
+ g_signals.m_internals->TransactionAddedToMempool.disconnect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1));
+ g_signals.m_internals->BlockConnected.disconnect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
+ g_signals.m_internals->BlockDisconnected.disconnect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));
+ g_signals.m_internals->UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));
+ g_signals.m_internals->NewPoWValidBlock.disconnect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
}
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.SyncTransaction.disconnect_all_slots();
- g_signals.UpdatedBlockTip.disconnect_all_slots();
- g_signals.NewPoWValidBlock.disconnect_all_slots();
+ g_signals.m_internals->BlockChecked.disconnect_all_slots();
+ g_signals.m_internals->Broadcast.disconnect_all_slots();
+ g_signals.m_internals->Inventory.disconnect_all_slots();
+ g_signals.m_internals->SetBestChain.disconnect_all_slots();
+ g_signals.m_internals->TransactionAddedToMempool.disconnect_all_slots();
+ g_signals.m_internals->BlockConnected.disconnect_all_slots();
+ g_signals.m_internals->BlockDisconnected.disconnect_all_slots();
+ g_signals.m_internals->UpdatedBlockTip.disconnect_all_slots();
+ g_signals.m_internals->NewPoWValidBlock.disconnect_all_slots();
+}
+
+void CMainSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
+ m_internals->UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload);
+}
+
+void CMainSignals::TransactionAddedToMempool(const CTransactionRef &ptx) {
+ m_internals->TransactionAddedToMempool(ptx);
+}
+
+void CMainSignals::BlockConnected(const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) {
+ m_internals->BlockConnected(pblock, pindex, vtxConflicted);
+}
+
+void CMainSignals::BlockDisconnected(const std::shared_ptr<const CBlock> &pblock) {
+ m_internals->BlockDisconnected(pblock);
+}
+
+void CMainSignals::SetBestChain(const CBlockLocator &locator) {
+ m_internals->SetBestChain(locator);
+}
+
+void CMainSignals::Inventory(const uint256 &hash) {
+ m_internals->Inventory(hash);
+}
+
+void CMainSignals::Broadcast(int64_t nBestBlockTime, CConnman* connman) {
+ m_internals->Broadcast(nBestBlockTime, connman);
+}
+
+void CMainSignals::BlockChecked(const CBlock& block, const CValidationState& state) {
+ m_internals->BlockChecked(block, state);
+}
+
+void CMainSignals::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock> &block) {
+ m_internals->NewPoWValidBlock(pindex, block);
}
diff --git a/src/validationinterface.h b/src/validationinterface.h
index 594072719c..d6da2bc1fd 100644
--- a/src/validationinterface.h
+++ b/src/validationinterface.h
@@ -6,20 +6,20 @@
#ifndef BITCOIN_VALIDATIONINTERFACE_H
#define BITCOIN_VALIDATIONINTERFACE_H
-#include <boost/signals2/signal.hpp>
-#include <boost/shared_ptr.hpp>
#include <memory>
+#include "primitives/transaction.h" // CTransaction(Ref)
+
class CBlock;
class CBlockIndex;
struct CBlockLocator;
class CBlockIndex;
class CConnman;
class CReserveScript;
-class CTransaction;
class CValidationInterface;
class CValidationState;
class uint256;
+class CScheduler;
// These functions dispatch to one or all registered wallets
@@ -32,46 +32,65 @@ void UnregisterAllValidationInterfaces();
class CValidationInterface {
protected:
+ /** Notifies listeners of updated block chain tip */
virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {}
- virtual void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, int posInBlock) {}
+ /** Notifies listeners of a transaction having been added to mempool. */
+ virtual void TransactionAddedToMempool(const CTransactionRef &ptxn) {}
+ /**
+ * Notifies listeners of a block being connected.
+ * Provides a vector of transactions evicted from the mempool as a result.
+ */
+ virtual void BlockConnected(const std::shared_ptr<const CBlock> &block, const CBlockIndex *pindex, const std::vector<CTransactionRef> &txnConflicted) {}
+ /** Notifies listeners of a block being disconnected */
+ virtual void BlockDisconnected(const std::shared_ptr<const CBlock> &block) {}
+ /** Notifies listeners of the new active block chain on-disk. */
virtual void SetBestChain(const CBlockLocator &locator) {}
- virtual void UpdatedTransaction(const uint256 &hash) {}
+ /** Notifies listeners about an inventory item being seen on the network. */
virtual void Inventory(const uint256 &hash) {}
+ /** Tells listeners to broadcast their data. */
virtual void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) {}
+ /**
+ * Notifies listeners of a block validation result.
+ * If the provided CValidationState IsValid, the provided block
+ * is guaranteed to be the current best block at the time the
+ * callback was generated (not necessarily now)
+ */
virtual void BlockChecked(const CBlock&, const CValidationState&) {}
- virtual void GetScriptForMining(boost::shared_ptr<CReserveScript>&) {};
- virtual void ResetRequestCount(const uint256 &hash) {};
+ /**
+ * Notifies listeners that a block which builds directly on our current tip
+ * has been received and connected to the headers tree, though not validated yet */
virtual void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& block) {};
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 CBlockIndex *, const CBlockIndex *, bool fInitialDownload)> UpdatedBlockTip;
- /** A posInBlock value for SyncTransaction which indicates the transaction was conflicted, disconnected, or not in a block */
- static const int SYNC_TRANSACTION_NOT_IN_BLOCK = -1;
- /** Notifies listeners of updated transaction data (transaction, and optionally the block it is found in. */
- boost::signals2::signal<void (const CTransaction &, const CBlockIndex *pindex, int posInBlock)> SyncTransaction;
- /** 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. */
- boost::signals2::signal<void (const CBlockLocator &)> SetBestChain;
- /** Notifies listeners about an inventory item being seen on the network. */
- boost::signals2::signal<void (const uint256 &)> Inventory;
- /** Tells listeners to broadcast their data. */
- boost::signals2::signal<void (int64_t nBestBlockTime, CConnman* connman)> 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;
- /**
- * Notifies listeners that a block which builds directly on our current tip
- * has been received and connected to the headers tree, though not validated yet */
- boost::signals2::signal<void (const CBlockIndex *, const std::shared_ptr<const CBlock>&)> NewPoWValidBlock;
+struct MainSignalsInstance;
+class CMainSignals {
+private:
+ std::unique_ptr<MainSignalsInstance> m_internals;
+
+ friend void ::RegisterValidationInterface(CValidationInterface*);
+ friend void ::UnregisterValidationInterface(CValidationInterface*);
+ friend void ::UnregisterAllValidationInterfaces();
+
+public:
+ /** Register a CScheduler to give callbacks which should run in the background (may only be called once) */
+ void RegisterBackgroundSignalScheduler(CScheduler& scheduler);
+ /** Unregister a CScheduler to give callbacks which should run in the background - these callbacks will now be dropped! */
+ void UnregisterBackgroundSignalScheduler();
+ /** Call any remaining callbacks on the calling thread */
+ void FlushBackgroundCallbacks();
+
+ void UpdatedBlockTip(const CBlockIndex *, const CBlockIndex *, bool fInitialDownload);
+ void TransactionAddedToMempool(const CTransactionRef &);
+ void BlockConnected(const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::vector<CTransactionRef> &);
+ void BlockDisconnected(const std::shared_ptr<const CBlock> &);
+ void SetBestChain(const CBlockLocator &);
+ void Inventory(const uint256 &);
+ void Broadcast(int64_t nBestBlockTime, CConnman* connman);
+ void BlockChecked(const CBlock&, const CValidationState&);
+ void NewPoWValidBlock(const CBlockIndex *, const std::shared_ptr<const CBlock>&);
};
CMainSignals& GetMainSignals();
diff --git a/src/version.h b/src/version.h
index 0f69b2f02b..d528212490 100644
--- a/src/version.h
+++ b/src/version.h
@@ -27,9 +27,6 @@ static const int CADDR_TIME_VERSION = 31402;
//! BIP 0031, pong message, is enabled for all versions AFTER this one
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;
diff --git a/src/versionbits.cpp b/src/versionbits.cpp
index d73f340510..64ae939672 100644
--- a/src/versionbits.cpp
+++ b/src/versionbits.cpp
@@ -3,10 +3,9 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "versionbits.h"
-
#include "consensus/params.h"
-const struct BIP9DeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_BITS_DEPLOYMENTS] = {
+const struct VBDeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_BITS_DEPLOYMENTS] = {
{
/*.name =*/ "testdummy",
/*.gbt_force =*/ true,
@@ -17,7 +16,7 @@ const struct BIP9DeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION
},
{
/*.name =*/ "segwit",
- /*.gbt_force =*/ false,
+ /*.gbt_force =*/ true,
}
};
@@ -29,14 +28,14 @@ ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex*
int64_t nTimeTimeout = EndTime(params);
// A block's state is always the same as that of the first of its period, so it is computed based on a pindexPrev whose height equals a multiple of nPeriod - 1.
- if (pindexPrev != NULL) {
+ if (pindexPrev != nullptr) {
pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod));
}
// Walk backwards in steps of nPeriod to find a pindexPrev whose information is known
std::vector<const CBlockIndex*> vToCompute;
while (cache.count(pindexPrev) == 0) {
- if (pindexPrev == NULL) {
+ if (pindexPrev == nullptr) {
// The genesis block is by definition defined.
cache[pindexPrev] = THRESHOLD_DEFINED;
break;
@@ -105,6 +104,36 @@ ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex*
return state;
}
+// return the numerical statistics of blocks signalling the specified BIP9 condition in this current period
+BIP9Stats AbstractThresholdConditionChecker::GetStateStatisticsFor(const CBlockIndex* pindex, const Consensus::Params& params) const
+{
+ BIP9Stats stats = {};
+
+ stats.period = Period(params);
+ stats.threshold = Threshold(params);
+
+ if (pindex == nullptr)
+ return stats;
+
+ // Find beginning of period
+ const CBlockIndex* pindexEndOfPrevPeriod = pindex->GetAncestor(pindex->nHeight - ((pindex->nHeight + 1) % stats.period));
+ stats.elapsed = pindex->nHeight - pindexEndOfPrevPeriod->nHeight;
+
+ // Count from current block to beginning of period
+ int count = 0;
+ const CBlockIndex* currentIndex = pindex;
+ while (pindexEndOfPrevPeriod->nHeight != currentIndex->nHeight){
+ if (Condition(currentIndex, params))
+ count++;
+ currentIndex = currentIndex->pprev;
+ }
+
+ stats.count = count;
+ stats.possible = (stats.period - stats.threshold ) >= (stats.elapsed - count);
+
+ return stats;
+}
+
int AbstractThresholdConditionChecker::GetStateSinceHeightFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
{
const ThresholdState initialState = GetStateFor(pindexPrev, params, cache);
@@ -121,12 +150,12 @@ int AbstractThresholdConditionChecker::GetStateSinceHeightFor(const CBlockIndex*
// right now pindexPrev points to the block prior to the block that we are computing for, thus:
// if we are computing for the last block of a period, then pindexPrev points to the second to last block of the period, and
// if we are computing for the first block of a period, then pindexPrev points to the last block of the previous period.
- // The parent of the genesis block is represented by NULL.
+ // The parent of the genesis block is represented by nullptr.
pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod));
const CBlockIndex* previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
- while (previousPeriodParent != NULL && GetStateFor(previousPeriodParent, params, cache) == initialState) {
+ while (previousPeriodParent != nullptr && GetStateFor(previousPeriodParent, params, cache) == initialState) {
pindexPrev = previousPeriodParent;
previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
}
@@ -145,28 +174,33 @@ private:
const Consensus::DeploymentPos id;
protected:
- int64_t BeginTime(const Consensus::Params& params) const { return params.vDeployments[id].nStartTime; }
- int64_t EndTime(const Consensus::Params& params) const { return params.vDeployments[id].nTimeout; }
- int Period(const Consensus::Params& params) const { return params.nMinerConfirmationWindow; }
- int Threshold(const Consensus::Params& params) const { return params.nRuleChangeActivationThreshold; }
+ int64_t BeginTime(const Consensus::Params& params) const override { return params.vDeployments[id].nStartTime; }
+ int64_t EndTime(const Consensus::Params& params) const override { return params.vDeployments[id].nTimeout; }
+ int Period(const Consensus::Params& params) const override { return params.nMinerConfirmationWindow; }
+ int Threshold(const Consensus::Params& params) const override { return params.nRuleChangeActivationThreshold; }
- bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const
+ bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const override
{
return (((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && (pindex->nVersion & Mask(params)) != 0);
}
public:
- VersionBitsConditionChecker(Consensus::DeploymentPos id_) : id(id_) {}
+ explicit VersionBitsConditionChecker(Consensus::DeploymentPos id_) : id(id_) {}
uint32_t Mask(const Consensus::Params& params) const { return ((uint32_t)1) << params.vDeployments[id].bit; }
};
-}
+} // namespace
ThresholdState VersionBitsState(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache)
{
return VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, cache.caches[pos]);
}
+BIP9Stats VersionBitsStatistics(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos)
+{
+ return VersionBitsConditionChecker(pos).GetStateStatisticsFor(pindexPrev, params);
+}
+
int VersionBitsStateSinceHeight(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache)
{
return VersionBitsConditionChecker(pos).GetStateSinceHeightFor(pindexPrev, params, cache.caches[pos]);
diff --git a/src/versionbits.h b/src/versionbits.h
index 7a929266aa..71dc0c8500 100644
--- a/src/versionbits.h
+++ b/src/versionbits.h
@@ -27,17 +27,25 @@ enum ThresholdState {
// A map that gives the state for blocks whose height is a multiple of Period().
// The map is indexed by the block's parent, however, so all keys in the map
-// will either be NULL or a block with (height + 1) % Period() == 0.
+// will either be nullptr or a block with (height + 1) % Period() == 0.
typedef std::map<const CBlockIndex*, ThresholdState> ThresholdConditionCache;
-struct BIP9DeploymentInfo {
+struct VBDeploymentInfo {
/** Deployment name */
const char *name;
/** Whether GBT clients can safely ignore this rule in simplified usage */
bool gbt_force;
};
-extern const struct BIP9DeploymentInfo VersionBitsDeploymentInfo[];
+struct BIP9Stats {
+ int period;
+ int threshold;
+ int elapsed;
+ int count;
+ bool possible;
+};
+
+extern const struct VBDeploymentInfo VersionBitsDeploymentInfo[];
/**
* Abstract class that implements BIP9-style threshold logic, and caches results.
@@ -51,6 +59,7 @@ protected:
virtual int Threshold(const Consensus::Params& params) const =0;
public:
+ BIP9Stats GetStateStatisticsFor(const CBlockIndex* pindex, const Consensus::Params& params) const;
// Note that the functions below take a pindexPrev as input: they compute information for block B based on its parent.
ThresholdState GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const;
int GetStateSinceHeightFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const;
@@ -64,6 +73,7 @@ struct VersionBitsCache
};
ThresholdState VersionBitsState(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache);
+BIP9Stats VersionBitsStatistics(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos);
int VersionBitsStateSinceHeight(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache);
uint32_t VersionBitsMask(const Consensus::Params& params, Consensus::DeploymentPos pos);
diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h
index eaf4ff8062..fc0e7c519e 100644
--- a/src/wallet/coincontrol.h
+++ b/src/wallet/coincontrol.h
@@ -5,7 +5,12 @@
#ifndef BITCOIN_WALLET_COINCONTROL_H
#define BITCOIN_WALLET_COINCONTROL_H
+#include "policy/feerate.h"
+#include "policy/fees.h"
#include "primitives/transaction.h"
+#include "wallet/wallet.h"
+
+#include <boost/optional.hpp>
/** Coin Control Features. */
class CCoinControl
@@ -16,14 +21,16 @@ public:
bool fAllowOtherInputs;
//! Includes watch only addresses which match the ISMINE_WATCH_SOLVABLE criteria
bool fAllowWatchOnly;
- //! Minimum absolute fee (not per kilobyte)
- CAmount nMinimumTotalFee;
- //! Override estimated feerate
+ //! Override automatic min/max checks on fee, m_feerate must be set if true
bool fOverrideFeeRate;
- //! Feerate to use if overrideFeeRate is true
- CFeeRate nFeeRate;
- //! Override the default confirmation target, 0 = use default
- int nConfirmTarget;
+ //! Override the default payTxFee if set
+ boost::optional<CFeeRate> m_feerate;
+ //! Override the default confirmation target if set
+ boost::optional<unsigned int> m_confirm_target;
+ //! Signal BIP-125 replace by fee.
+ bool signalRbf;
+ //! Fee estimation mode to control arguments to estimateSmartFee
+ FeeEstimateMode m_fee_mode;
CCoinControl()
{
@@ -36,10 +43,11 @@ public:
fAllowOtherInputs = false;
fAllowWatchOnly = false;
setSelected.clear();
- nMinimumTotalFee = 0;
- nFeeRate = CFeeRate(0);
+ m_feerate.reset();
fOverrideFeeRate = false;
- nConfirmTarget = 0;
+ m_confirm_target.reset();
+ signalRbf = fWalletRbf;
+ m_fee_mode = FeeEstimateMode::UNSET;
}
bool HasSelected() const
diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp
index fc318c1612..8db3bfd69c 100644
--- a/src/wallet/crypter.cpp
+++ b/src/wallet/crypter.cpp
@@ -12,7 +12,6 @@
#include <string>
#include <vector>
-#include <boost/foreach.hpp>
int CCrypter::BytesToKeySHA512AES(const std::vector<unsigned char>& chSalt, const SecureString& strKeyData, int count, unsigned char *key,unsigned char *iv) const
{
@@ -28,8 +27,7 @@ int CCrypter::BytesToKeySHA512AES(const std::vector<unsigned char>& chSalt, cons
CSHA512 di;
di.Write((const unsigned char*)strKeyData.c_str(), strKeyData.size());
- if(chSalt.size())
- di.Write(&chSalt[0], chSalt.size());
+ di.Write(chSalt.data(), chSalt.size());
di.Finalize(buf);
for(int i = 0; i != count - 1; i++)
@@ -83,7 +81,7 @@ bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned
vchCiphertext.resize(vchPlaintext.size() + AES_BLOCKSIZE);
AES256CBCEncrypt enc(vchKey.data(), vchIV.data(), true);
- size_t nLen = enc.Encrypt(&vchPlaintext[0], vchPlaintext.size(), &vchCiphertext[0]);
+ size_t nLen = enc.Encrypt(&vchPlaintext[0], vchPlaintext.size(), vchCiphertext.data());
if(nLen < vchPlaintext.size())
return false;
vchCiphertext.resize(nLen);
@@ -102,7 +100,7 @@ bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingM
vchPlaintext.resize(nLen);
AES256CBCDecrypt dec(vchKey.data(), vchIV.data(), true);
- nLen = dec.Decrypt(&vchCiphertext[0], vchCiphertext.size(), &vchPlaintext[0]);
+ nLen = dec.Decrypt(vchCiphertext.data(), vchCiphertext.size(), &vchPlaintext[0]);
if(nLen == 0)
return false;
vchPlaintext.resize(nLen);
@@ -114,7 +112,7 @@ static bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMateri
{
CCrypter cKeyCrypter;
std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
- memcpy(&chIV[0], &nIV, WALLET_CRYPTO_IV_SIZE);
+ memcpy(chIV.data(), &nIV, WALLET_CRYPTO_IV_SIZE);
if(!cKeyCrypter.SetKey(vMasterKey, chIV))
return false;
return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext);
@@ -124,7 +122,7 @@ static bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<u
{
CCrypter cKeyCrypter;
std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
- memcpy(&chIV[0], &nIV, WALLET_CRYPTO_IV_SIZE);
+ memcpy(chIV.data(), &nIV, WALLET_CRYPTO_IV_SIZE);
if(!cKeyCrypter.SetKey(vMasterKey, chIV))
return false;
return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));
@@ -274,7 +272,6 @@ bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) co
// Check for watch-only pubkeys
return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
}
- return false;
}
bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
@@ -285,7 +282,7 @@ bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
return false;
fUseCrypto = true;
- BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys)
+ for (KeyMap::value_type& mKey : mapKeys)
{
const CKey &key = mKey.second;
CPubKey vchPubKey = key.GetPubKey();
diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h
index 275e435f73..1416ae7d02 100644
--- a/src/wallet/crypter.h
+++ b/src/wallet/crypter.h
@@ -9,7 +9,7 @@
#include "serialize.h"
#include "support/allocators/secure.h"
-class uint256;
+#include <atomic>
const unsigned int WALLET_CRYPTO_KEY_SIZE = 32;
const unsigned int WALLET_CRYPTO_SALT_SIZE = 8;
@@ -18,13 +18,13 @@ const unsigned int WALLET_CRYPTO_IV_SIZE = 16;
/**
* Private key encryption is done based on a CMasterKey,
* which holds a salt and random encryption key.
- *
+ *
* CMasterKeys are encrypted using AES-256-CBC using a key
* derived using derivation method nDerivationMethod
* (0 == EVP_sha512()) and derivation iterations nDeriveIterations.
* vchOtherDerivationParameters is provided for alternative algorithms
* which may require more parameters (such as scrypt).
- *
+ *
* Wallet Private Keys are then encrypted using AES-256-CBC
* with the double-sha256 of the public key as the IV, and the
* master key's key as the encryption key (see keystore.[ch]).
@@ -115,13 +115,12 @@ public:
class CCryptoKeyStore : public CBasicKeyStore
{
private:
- CryptedKeyMap mapCryptedKeys;
CKeyingMaterial vMasterKey;
//! if fUseCrypto is true, mapKeys must be empty
//! if fUseCrypto is false, vMasterKey must be empty
- bool fUseCrypto;
+ std::atomic<bool> fUseCrypto;
//! keeps track of whether Unlock has run a thorough check before
bool fDecryptionThoroughlyChecked;
@@ -133,6 +132,7 @@ protected:
bool EncryptKeys(CKeyingMaterial& vMasterKeyIn);
bool Unlock(const CKeyingMaterial& vMasterKeyIn);
+ CryptedKeyMap mapCryptedKeys;
public:
CCryptoKeyStore() : fUseCrypto(false), fDecryptionThoroughlyChecked(false)
@@ -159,33 +159,31 @@ public:
bool Lock();
virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
- bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
- bool HaveKey(const CKeyID &address) const
+ bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override;
+ bool HaveKey(const CKeyID &address) const override
{
{
LOCK(cs_KeyStore);
- if (!IsCrypted())
+ if (!IsCrypted()) {
return CBasicKeyStore::HaveKey(address);
+ }
return mapCryptedKeys.count(address) > 0;
}
return false;
}
- bool GetKey(const CKeyID &address, CKey& keyOut) const;
- bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const;
- void GetKeys(std::set<CKeyID> &setAddress) const
+ bool GetKey(const CKeyID &address, CKey& keyOut) const override;
+ bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;
+ std::set<CKeyID> GetKeys() const override
{
- if (!IsCrypted())
- {
- CBasicKeyStore::GetKeys(setAddress);
- return;
+ LOCK(cs_KeyStore);
+ if (!IsCrypted()) {
+ return CBasicKeyStore::GetKeys();
}
- setAddress.clear();
- CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
- while (mi != mapCryptedKeys.end())
- {
- setAddress.insert((*mi).first);
- mi++;
+ std::set<CKeyID> set_address;
+ for (const auto& mi : mapCryptedKeys) {
+ set_address.insert(mi.first);
}
+ return set_address;
}
/**
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index 800e1f4e29..d66ba48421 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -6,6 +6,7 @@
#include "db.h"
#include "addrman.h"
+#include "fs.h"
#include "hash.h"
#include "protocol.h"
#include "util.h"
@@ -17,15 +18,7 @@
#include <sys/stat.h>
#endif
-#include <boost/filesystem.hpp>
#include <boost/thread.hpp>
-#include <boost/version.hpp>
-
-using namespace std;
-
-
-unsigned int nWalletDBUpdated;
-
//
// CDB
@@ -54,7 +47,7 @@ void CDBEnv::Reset()
fMockDb = false;
}
-CDBEnv::CDBEnv() : dbenv(NULL)
+CDBEnv::CDBEnv() : dbenv(nullptr)
{
Reset();
}
@@ -63,7 +56,7 @@ CDBEnv::~CDBEnv()
{
EnvShutdown();
delete dbenv;
- dbenv = NULL;
+ dbenv = nullptr;
}
void CDBEnv::Close()
@@ -71,7 +64,7 @@ void CDBEnv::Close()
EnvShutdown();
}
-bool CDBEnv::Open(const boost::filesystem::path& pathIn)
+bool CDBEnv::Open(const fs::path& pathIn)
{
if (fDbEnvInit)
return true;
@@ -79,13 +72,13 @@ bool CDBEnv::Open(const boost::filesystem::path& pathIn)
boost::this_thread::interruption_point();
strPath = pathIn.string();
- boost::filesystem::path pathLogDir = pathIn / "database";
- TryCreateDirectory(pathLogDir);
- boost::filesystem::path pathErrorFile = pathIn / "db.log";
+ fs::path pathLogDir = pathIn / "database";
+ TryCreateDirectories(pathLogDir);
+ fs::path pathErrorFile = pathIn / "db.log";
LogPrintf("CDBEnv::Open: LogDir=%s ErrorFile=%s\n", pathLogDir.string(), pathErrorFile.string());
unsigned int nEnvFlags = 0;
- if (GetBoolArg("-privdb", DEFAULT_WALLET_PRIVDB))
+ if (gArgs.GetBoolArg("-privdb", DEFAULT_WALLET_PRIVDB))
nEnvFlags |= DB_PRIVATE;
dbenv->set_lg_dir(pathLogDir.string().c_str());
@@ -94,7 +87,7 @@ bool CDBEnv::Open(const boost::filesystem::path& pathIn)
dbenv->set_lg_max(1048576);
dbenv->set_lk_max_locks(40000);
dbenv->set_lk_max_objects(40000);
- dbenv->set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug
+ dbenv->set_errfile(fsbridge::fopen(pathErrorFile, "a")); /// debug
dbenv->set_flags(DB_AUTO_COMMIT, 1);
dbenv->set_flags(DB_TXN_WRITE_NOSYNC, 1);
dbenv->log_set_config(DB_LOG_AUTO_REMOVE, 1);
@@ -108,8 +101,10 @@ bool CDBEnv::Open(const boost::filesystem::path& pathIn)
DB_RECOVER |
nEnvFlags,
S_IRUSR | S_IWUSR);
- if (ret != 0)
+ if (ret != 0) {
+ dbenv->close(0);
return error("CDBEnv::Open: Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret));
+ }
fDbEnvInit = true;
fMockDb = false;
@@ -119,11 +114,11 @@ bool CDBEnv::Open(const boost::filesystem::path& pathIn)
void CDBEnv::MakeMock()
{
if (fDbEnvInit)
- throw runtime_error("CDBEnv::MakeMock: Already initialized");
+ throw std::runtime_error("CDBEnv::MakeMock: Already initialized");
boost::this_thread::interruption_point();
- LogPrint("db", "CDBEnv::MakeMock\n");
+ LogPrint(BCLog::DB, "CDBEnv::MakeMock\n");
dbenv->set_cachesize(1, 0, 1);
dbenv->set_lg_bsize(10485760 * 4);
@@ -132,7 +127,7 @@ void CDBEnv::MakeMock()
dbenv->set_lk_max_objects(10000);
dbenv->set_flags(DB_AUTO_COMMIT, 1);
dbenv->log_set_config(DB_LOG_IN_MEMORY, 1);
- int ret = dbenv->open(NULL,
+ int ret = dbenv->open(nullptr,
DB_CREATE |
DB_INIT_LOCK |
DB_INIT_LOG |
@@ -142,29 +137,153 @@ void CDBEnv::MakeMock()
DB_PRIVATE,
S_IRUSR | S_IWUSR);
if (ret > 0)
- throw runtime_error(strprintf("CDBEnv::MakeMock: Error %d opening database environment.", ret));
+ throw std::runtime_error(strprintf("CDBEnv::MakeMock: Error %d opening database environment.", ret));
fDbEnvInit = true;
fMockDb = true;
}
-CDBEnv::VerifyResult CDBEnv::Verify(const std::string& strFile, bool (*recoverFunc)(CDBEnv& dbenv, const std::string& strFile))
+CDBEnv::VerifyResult CDBEnv::Verify(const std::string& strFile, recoverFunc_type recoverFunc, std::string& out_backup_filename)
{
LOCK(cs_db);
assert(mapFileUseCount.count(strFile) == 0);
Db db(dbenv, 0);
- int result = db.verify(strFile.c_str(), NULL, NULL, 0);
+ int result = db.verify(strFile.c_str(), nullptr, nullptr, 0);
if (result == 0)
return VERIFY_OK;
- else if (recoverFunc == NULL)
+ else if (recoverFunc == nullptr)
return RECOVER_FAIL;
// Try to recover:
- bool fRecovered = (*recoverFunc)(*this, strFile);
+ bool fRecovered = (*recoverFunc)(strFile, out_backup_filename);
return (fRecovered ? RECOVER_OK : RECOVER_FAIL);
}
+bool CDB::Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& newFilename)
+{
+ // Recovery procedure:
+ // move wallet file to walletfilename.timestamp.bak
+ // Call Salvage with fAggressive=true to
+ // get as much data as possible.
+ // Rewrite salvaged data to fresh wallet file
+ // Set -rescan so any missing transactions will be
+ // found.
+ int64_t now = GetTime();
+ newFilename = strprintf("%s.%d.bak", filename, now);
+
+ int result = bitdb.dbenv->dbrename(nullptr, filename.c_str(), nullptr,
+ newFilename.c_str(), DB_AUTO_COMMIT);
+ if (result == 0)
+ LogPrintf("Renamed %s to %s\n", filename, newFilename);
+ else
+ {
+ LogPrintf("Failed to rename %s to %s\n", filename, newFilename);
+ return false;
+ }
+
+ std::vector<CDBEnv::KeyValPair> salvagedData;
+ bool fSuccess = bitdb.Salvage(newFilename, true, salvagedData);
+ if (salvagedData.empty())
+ {
+ LogPrintf("Salvage(aggressive) found no records in %s.\n", newFilename);
+ return false;
+ }
+ LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size());
+
+ std::unique_ptr<Db> pdbCopy(new Db(bitdb.dbenv, 0));
+ int ret = pdbCopy->open(nullptr, // Txn pointer
+ filename.c_str(), // Filename
+ "main", // Logical db name
+ DB_BTREE, // Database type
+ DB_CREATE, // Flags
+ 0);
+ if (ret > 0) {
+ LogPrintf("Cannot create database file %s\n", filename);
+ pdbCopy->close(0);
+ return false;
+ }
+
+ DbTxn* ptxn = bitdb.TxnBegin();
+ for (CDBEnv::KeyValPair& row : salvagedData)
+ {
+ if (recoverKVcallback)
+ {
+ CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION);
+ CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION);
+ if (!(*recoverKVcallback)(callbackDataIn, ssKey, ssValue))
+ continue;
+ }
+ Dbt datKey(&row.first[0], row.first.size());
+ Dbt datValue(&row.second[0], row.second.size());
+ int ret2 = pdbCopy->put(ptxn, &datKey, &datValue, DB_NOOVERWRITE);
+ if (ret2 > 0)
+ fSuccess = false;
+ }
+ ptxn->commit(0);
+ pdbCopy->close(0);
+
+ return fSuccess;
+}
+
+bool CDB::VerifyEnvironment(const std::string& walletFile, const fs::path& dataDir, std::string& errorStr)
+{
+ LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0));
+ LogPrintf("Using wallet %s\n", walletFile);
+
+ // Wallet file must be a plain filename without a directory
+ if (walletFile != fs::basename(walletFile) + fs::extension(walletFile))
+ {
+ errorStr = strprintf(_("Wallet %s resides outside data directory %s"), walletFile, dataDir.string());
+ return false;
+ }
+
+ if (!bitdb.Open(dataDir))
+ {
+ // try moving the database env out of the way
+ fs::path pathDatabase = dataDir / "database";
+ fs::path pathDatabaseBak = dataDir / strprintf("database.%d.bak", GetTime());
+ try {
+ fs::rename(pathDatabase, pathDatabaseBak);
+ LogPrintf("Moved old %s to %s. Retrying.\n", pathDatabase.string(), pathDatabaseBak.string());
+ } catch (const fs::filesystem_error&) {
+ // failure is ok (well, not really, but it's not worse than what we started with)
+ }
+
+ // try again
+ if (!bitdb.Open(dataDir)) {
+ // if it still fails, it probably means we can't even create the database env
+ errorStr = strprintf(_("Error initializing wallet database environment %s!"), GetDataDir());
+ return false;
+ }
+ }
+ return true;
+}
+
+bool CDB::VerifyDatabaseFile(const std::string& walletFile, const fs::path& dataDir, std::string& warningStr, std::string& errorStr, CDBEnv::recoverFunc_type recoverFunc)
+{
+ if (fs::exists(dataDir / walletFile))
+ {
+ std::string backup_filename;
+ CDBEnv::VerifyResult r = bitdb.Verify(walletFile, recoverFunc, backup_filename);
+ if (r == CDBEnv::RECOVER_OK)
+ {
+ warningStr = strprintf(_("Warning: Wallet file corrupt, data salvaged!"
+ " Original %s saved as %s in %s; if"
+ " your balance or transactions are incorrect you should"
+ " restore from a backup."),
+ walletFile, backup_filename, dataDir);
+ }
+ if (r == CDBEnv::RECOVER_FAIL)
+ {
+ errorStr = strprintf(_("%s corrupt, salvage failed"), walletFile);
+ return false;
+ }
+ }
+ // also return true if files does not exists
+ return true;
+}
+
/* End of headers, beginning of key/value data */
static const char *HEADER_END = "HEADER=END";
/* End of key/value data */
@@ -179,10 +298,10 @@ bool CDBEnv::Salvage(const std::string& strFile, bool fAggressive, std::vector<C
if (fAggressive)
flags |= DB_AGGRESSIVE;
- stringstream strDump;
+ std::stringstream strDump;
Db db(dbenv, 0);
- int result = db.verify(strFile.c_str(), NULL, &strDump, flags);
+ int result = db.verify(strFile.c_str(), nullptr, &strDump, flags);
if (result == DB_VERIFY_BAD) {
LogPrintf("CDBEnv::Salvage: Database salvage found errors, all data may not be recoverable.\n");
if (!fAggressive) {
@@ -203,7 +322,7 @@ bool CDBEnv::Salvage(const std::string& strFile, bool fAggressive, std::vector<C
// ... repeated
// DATA=END
- string strLine;
+ std::string strLine;
while (!strDump.eof() && strLine != HEADER_END)
getline(strDump, strLine); // Skip past header
@@ -240,40 +359,43 @@ void CDBEnv::CheckpointLSN(const std::string& strFile)
}
-CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnCloseIn) : pdb(NULL), activeTxn(NULL)
+CDB::CDB(CWalletDBWrapper& dbw, const char* pszMode, bool fFlushOnCloseIn) : pdb(nullptr), activeTxn(nullptr)
{
- int ret;
fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w'));
fFlushOnClose = fFlushOnCloseIn;
- if (strFilename.empty())
+ env = dbw.env;
+ if (dbw.IsDummy()) {
return;
+ }
+ const std::string &strFilename = dbw.strFile;
- bool fCreate = strchr(pszMode, 'c') != NULL;
+ bool fCreate = strchr(pszMode, 'c') != nullptr;
unsigned int nFlags = DB_THREAD;
if (fCreate)
nFlags |= DB_CREATE;
{
- LOCK(bitdb.cs_db);
- if (!bitdb.Open(GetDataDir()))
- throw runtime_error("CDB: Failed to open database environment.");
+ LOCK(env->cs_db);
+ if (!env->Open(GetDataDir()))
+ throw std::runtime_error("CDB: Failed to open database environment.");
strFile = strFilename;
- ++bitdb.mapFileUseCount[strFile];
- pdb = bitdb.mapDb[strFile];
- if (pdb == NULL) {
- pdb = new Db(bitdb.dbenv, 0);
+ ++env->mapFileUseCount[strFile];
+ pdb = env->mapDb[strFile];
+ if (pdb == nullptr) {
+ int ret;
+ pdb = new Db(env->dbenv, 0);
- bool fMockDb = bitdb.IsMock();
+ bool fMockDb = env->IsMock();
if (fMockDb) {
DbMpoolFile* mpf = pdb->get_mpf();
ret = mpf->set_flags(DB_MPOOL_NOFILE, 1);
if (ret != 0)
- throw runtime_error(strprintf("CDB: Failed to configure for no temp file backing for database %s", strFile));
+ throw std::runtime_error(strprintf("CDB: Failed to configure for no temp file backing for database %s", strFile));
}
- ret = pdb->open(NULL, // Txn pointer
- fMockDb ? NULL : strFile.c_str(), // Filename
+ ret = pdb->open(nullptr, // Txn pointer
+ fMockDb ? nullptr : strFile.c_str(), // Filename
fMockDb ? strFile.c_str() : "main", // Logical db name
DB_BTREE, // Database type
nFlags, // Flags
@@ -281,20 +403,20 @@ CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnClose
if (ret != 0) {
delete pdb;
- pdb = NULL;
- --bitdb.mapFileUseCount[strFile];
+ pdb = nullptr;
+ --env->mapFileUseCount[strFile];
strFile = "";
- throw runtime_error(strprintf("CDB: Error %d, can't open database %s", ret, strFilename));
+ throw std::runtime_error(strprintf("CDB: Error %d, can't open database %s", ret, strFilename));
}
- if (fCreate && !Exists(string("version"))) {
+ if (fCreate && !Exists(std::string("version"))) {
bool fTmp = fReadOnly;
fReadOnly = false;
WriteVersion(CLIENT_VERSION);
fReadOnly = fTmp;
}
- bitdb.mapDb[strFile] = pdb;
+ env->mapDb[strFile] = pdb;
}
}
}
@@ -309,7 +431,12 @@ void CDB::Flush()
if (fReadOnly)
nMinutes = 1;
- bitdb.dbenv->txn_checkpoint(nMinutes ? GetArg("-dblogsize", DEFAULT_WALLET_DBLOGSIZE) * 1024 : 0, nMinutes, 0);
+ env->dbenv->txn_checkpoint(nMinutes ? gArgs.GetArg("-dblogsize", DEFAULT_WALLET_DBLOGSIZE) * 1024 : 0, nMinutes, 0);
+}
+
+void CWalletDBWrapper::IncrementUpdateCounter()
+{
+ ++nUpdateCounter;
}
void CDB::Close()
@@ -318,60 +445,56 @@ void CDB::Close()
return;
if (activeTxn)
activeTxn->abort();
- activeTxn = NULL;
- pdb = NULL;
+ activeTxn = nullptr;
+ pdb = nullptr;
if (fFlushOnClose)
Flush();
{
- LOCK(bitdb.cs_db);
- --bitdb.mapFileUseCount[strFile];
+ LOCK(env->cs_db);
+ --env->mapFileUseCount[strFile];
}
}
-void CDBEnv::CloseDb(const string& strFile)
+void CDBEnv::CloseDb(const std::string& strFile)
{
{
LOCK(cs_db);
- if (mapDb[strFile] != NULL) {
+ if (mapDb[strFile] != nullptr) {
// Close the database handle
Db* pdb = mapDb[strFile];
pdb->close(0);
delete pdb;
- mapDb[strFile] = NULL;
+ mapDb[strFile] = nullptr;
}
}
}
-bool CDBEnv::RemoveDb(const string& strFile)
-{
- this->CloseDb(strFile);
-
- LOCK(cs_db);
- int rc = dbenv->dbremove(NULL, strFile.c_str(), NULL, DB_AUTO_COMMIT);
- return (rc == 0);
-}
-
-bool CDB::Rewrite(const string& strFile, const char* pszSkip)
+bool CDB::Rewrite(CWalletDBWrapper& dbw, const char* pszSkip)
{
+ if (dbw.IsDummy()) {
+ return true;
+ }
+ CDBEnv *env = dbw.env;
+ const std::string& strFile = dbw.strFile;
while (true) {
{
- LOCK(bitdb.cs_db);
- if (!bitdb.mapFileUseCount.count(strFile) || bitdb.mapFileUseCount[strFile] == 0) {
+ LOCK(env->cs_db);
+ if (!env->mapFileUseCount.count(strFile) || env->mapFileUseCount[strFile] == 0) {
// Flush log data to the dat file
- bitdb.CloseDb(strFile);
- bitdb.CheckpointLSN(strFile);
- bitdb.mapFileUseCount.erase(strFile);
+ env->CloseDb(strFile);
+ env->CheckpointLSN(strFile);
+ env->mapFileUseCount.erase(strFile);
bool fSuccess = true;
LogPrintf("CDB::Rewrite: Rewriting %s...\n", strFile);
- string strFileRes = strFile + ".rewrite";
+ std::string strFileRes = strFile + ".rewrite";
{ // surround usage of db with extra {}
- CDB db(strFile.c_str(), "r");
- Db* pdbCopy = new Db(bitdb.dbenv, 0);
+ CDB db(dbw, "r");
+ Db* pdbCopy = new Db(env->dbenv, 0);
- int ret = pdbCopy->open(NULL, // Txn pointer
+ int ret = pdbCopy->open(nullptr, // Txn pointer
strFileRes.c_str(), // Filename
"main", // Logical db name
DB_BTREE, // Database type
@@ -406,24 +529,26 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip)
}
Dbt datKey(ssKey.data(), ssKey.size());
Dbt datValue(ssValue.data(), ssValue.size());
- int ret2 = pdbCopy->put(NULL, &datKey, &datValue, DB_NOOVERWRITE);
+ int ret2 = pdbCopy->put(nullptr, &datKey, &datValue, DB_NOOVERWRITE);
if (ret2 > 0)
fSuccess = false;
}
if (fSuccess) {
db.Close();
- bitdb.CloseDb(strFile);
+ env->CloseDb(strFile);
if (pdbCopy->close(0))
fSuccess = false;
- delete pdbCopy;
+ } else {
+ pdbCopy->close(0);
}
+ delete pdbCopy;
}
if (fSuccess) {
- Db dbA(bitdb.dbenv, 0);
- if (dbA.remove(strFile.c_str(), NULL, 0))
+ Db dbA(env->dbenv, 0);
+ if (dbA.remove(strFile.c_str(), nullptr, 0))
fSuccess = false;
- Db dbB(bitdb.dbenv, 0);
- if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0))
+ Db dbB(env->dbenv, 0);
+ if (dbB.rename(strFileRes.c_str(), nullptr, strFile.c_str(), 0))
fSuccess = false;
}
if (!fSuccess)
@@ -433,7 +558,6 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip)
}
MilliSleep(100);
}
- return false;
}
@@ -441,38 +565,129 @@ void CDBEnv::Flush(bool fShutdown)
{
int64_t nStart = GetTimeMillis();
// Flush log data to the actual data file on all files that are not in use
- LogPrint("db", "CDBEnv::Flush: Flush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started");
+ LogPrint(BCLog::DB, "CDBEnv::Flush: Flush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started");
if (!fDbEnvInit)
return;
{
LOCK(cs_db);
- map<string, int>::iterator mi = mapFileUseCount.begin();
+ std::map<std::string, int>::iterator mi = mapFileUseCount.begin();
while (mi != mapFileUseCount.end()) {
- string strFile = (*mi).first;
+ std::string strFile = (*mi).first;
int nRefCount = (*mi).second;
- LogPrint("db", "CDBEnv::Flush: Flushing %s (refcount = %d)...\n", strFile, nRefCount);
+ LogPrint(BCLog::DB, "CDBEnv::Flush: Flushing %s (refcount = %d)...\n", strFile, nRefCount);
if (nRefCount == 0) {
// Move log data to the dat file
CloseDb(strFile);
- LogPrint("db", "CDBEnv::Flush: %s checkpoint\n", strFile);
+ LogPrint(BCLog::DB, "CDBEnv::Flush: %s checkpoint\n", strFile);
dbenv->txn_checkpoint(0, 0, 0);
- LogPrint("db", "CDBEnv::Flush: %s detach\n", strFile);
+ LogPrint(BCLog::DB, "CDBEnv::Flush: %s detach\n", strFile);
if (!fMockDb)
dbenv->lsn_reset(strFile.c_str(), 0);
- LogPrint("db", "CDBEnv::Flush: %s closed\n", strFile);
+ LogPrint(BCLog::DB, "CDBEnv::Flush: %s closed\n", strFile);
mapFileUseCount.erase(mi++);
} else
mi++;
}
- LogPrint("db", "CDBEnv::Flush: Flush(%s)%s took %15dms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started", GetTimeMillis() - nStart);
+ LogPrint(BCLog::DB, "CDBEnv::Flush: Flush(%s)%s took %15dms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started", GetTimeMillis() - nStart);
if (fShutdown) {
char** listp;
if (mapFileUseCount.empty()) {
dbenv->log_archive(&listp, DB_ARCH_REMOVE);
Close();
if (!fMockDb)
- boost::filesystem::remove_all(boost::filesystem::path(strPath) / "database");
+ fs::remove_all(fs::path(strPath) / "database");
+ }
+ }
+ }
+}
+
+bool CDB::PeriodicFlush(CWalletDBWrapper& dbw)
+{
+ if (dbw.IsDummy()) {
+ return true;
+ }
+ bool ret = false;
+ CDBEnv *env = dbw.env;
+ const std::string& strFile = dbw.strFile;
+ TRY_LOCK(bitdb.cs_db,lockDb);
+ if (lockDb)
+ {
+ // Don't do this if any databases are in use
+ int nRefCount = 0;
+ std::map<std::string, int>::iterator mit = env->mapFileUseCount.begin();
+ while (mit != env->mapFileUseCount.end())
+ {
+ nRefCount += (*mit).second;
+ mit++;
+ }
+
+ if (nRefCount == 0)
+ {
+ boost::this_thread::interruption_point();
+ std::map<std::string, int>::iterator mi = env->mapFileUseCount.find(strFile);
+ if (mi != env->mapFileUseCount.end())
+ {
+ LogPrint(BCLog::DB, "Flushing %s\n", strFile);
+ int64_t nStart = GetTimeMillis();
+
+ // Flush wallet file so it's self contained
+ env->CloseDb(strFile);
+ env->CheckpointLSN(strFile);
+
+ env->mapFileUseCount.erase(mi++);
+ LogPrint(BCLog::DB, "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart);
+ ret = true;
+ }
+ }
+ }
+
+ return ret;
+}
+
+bool CWalletDBWrapper::Rewrite(const char* pszSkip)
+{
+ return CDB::Rewrite(*this, pszSkip);
+}
+
+bool CWalletDBWrapper::Backup(const std::string& strDest)
+{
+ if (IsDummy()) {
+ return false;
+ }
+ while (true)
+ {
+ {
+ LOCK(env->cs_db);
+ if (!env->mapFileUseCount.count(strFile) || env->mapFileUseCount[strFile] == 0)
+ {
+ // Flush log data to the dat file
+ env->CloseDb(strFile);
+ env->CheckpointLSN(strFile);
+ env->mapFileUseCount.erase(strFile);
+
+ // Copy wallet file
+ fs::path pathSrc = GetDataDir() / strFile;
+ fs::path pathDest(strDest);
+ if (fs::is_directory(pathDest))
+ pathDest /= strFile;
+
+ try {
+ fs::copy_file(pathSrc, pathDest, fs::copy_option::overwrite_if_exists);
+ LogPrintf("copied %s to %s\n", strFile, pathDest.string());
+ return true;
+ } catch (const fs::filesystem_error& e) {
+ LogPrintf("error copying %s to %s - %s\n", strFile, pathDest.string(), e.what());
+ return false;
+ }
}
}
+ MilliSleep(100);
+ }
+}
+
+void CWalletDBWrapper::Flush(bool shutdown)
+{
+ if (!IsDummy()) {
+ env->Flush(shutdown);
}
}
diff --git a/src/wallet/db.h b/src/wallet/db.h
index bc15f2147f..14283ac8f8 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -7,30 +7,28 @@
#define BITCOIN_WALLET_DB_H
#include "clientversion.h"
+#include "fs.h"
#include "serialize.h"
#include "streams.h"
#include "sync.h"
#include "version.h"
+#include <atomic>
#include <map>
#include <string>
#include <vector>
-#include <boost/filesystem/path.hpp>
-
#include <db_cxx.h>
static const unsigned int DEFAULT_WALLET_DBLOGSIZE = 100;
static const bool DEFAULT_WALLET_PRIVDB = true;
-extern unsigned int nWalletDBUpdated;
-
class CDBEnv
{
private:
bool fDbEnvInit;
bool fMockDb;
- // Don't change into boost::filesystem::path, as that can result in
+ // Don't change into fs::path, as that can result in
// shutdown problems/crashes caused by a static initialized internal pointer.
std::string strPath;
@@ -47,7 +45,7 @@ public:
void Reset();
void MakeMock();
- bool IsMock() { return fMockDb; }
+ bool IsMock() const { return fMockDb; }
/**
* Verify that database file strFile is OK. If it is not,
@@ -58,7 +56,8 @@ public:
enum VerifyResult { VERIFY_OK,
RECOVER_OK,
RECOVER_FAIL };
- VerifyResult Verify(const std::string& strFile, bool (*recoverFunc)(CDBEnv& dbenv, const std::string& strFile));
+ typedef bool (*recoverFunc_type)(const std::string& strFile, std::string& out_backup_filename);
+ VerifyResult Verify(const std::string& strFile, recoverFunc_type recoverFunc, std::string& out_backup_filename);
/**
* Salvage data from a file that Verify says is bad.
* fAggressive sets the DB_AGGRESSIVE flag (see berkeley DB->verify() method documentation).
@@ -69,26 +68,78 @@ public:
typedef std::pair<std::vector<unsigned char>, std::vector<unsigned char> > KeyValPair;
bool Salvage(const std::string& strFile, bool fAggressive, std::vector<KeyValPair>& vResult);
- bool Open(const boost::filesystem::path& path);
+ bool Open(const fs::path& path);
void Close();
void Flush(bool fShutdown);
void CheckpointLSN(const std::string& strFile);
void CloseDb(const std::string& strFile);
- bool RemoveDb(const std::string& strFile);
DbTxn* TxnBegin(int flags = DB_TXN_WRITE_NOSYNC)
{
- DbTxn* ptxn = NULL;
- int ret = dbenv->txn_begin(NULL, &ptxn, flags);
+ DbTxn* ptxn = nullptr;
+ int ret = dbenv->txn_begin(nullptr, &ptxn, flags);
if (!ptxn || ret != 0)
- return NULL;
+ return nullptr;
return ptxn;
}
};
extern CDBEnv bitdb;
+/** An instance of this class represents one database.
+ * For BerkeleyDB this is just a (env, strFile) tuple.
+ **/
+class CWalletDBWrapper
+{
+ friend class CDB;
+public:
+ /** Create dummy DB handle */
+ CWalletDBWrapper() : nUpdateCounter(0), nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0), env(nullptr)
+ {
+ }
+
+ /** Create DB handle to real database */
+ CWalletDBWrapper(CDBEnv *env_in, const std::string &strFile_in) :
+ nUpdateCounter(0), nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0), env(env_in), strFile(strFile_in)
+ {
+ }
+
+ /** Rewrite the entire database on disk, with the exception of key pszSkip if non-zero
+ */
+ bool Rewrite(const char* pszSkip=nullptr);
+
+ /** Back up the entire database to a file.
+ */
+ bool Backup(const std::string& strDest);
+
+ /** Get a name for this database, for debugging etc.
+ */
+ std::string GetName() const { return strFile; }
+
+ /** Make sure all changes are flushed to disk.
+ */
+ void Flush(bool shutdown);
+
+ void IncrementUpdateCounter();
+
+ std::atomic<unsigned int> nUpdateCounter;
+ unsigned int nLastSeen;
+ unsigned int nLastFlushed;
+ int64_t nLastWalletUpdate;
+
+private:
+ /** BerkeleyDB specific */
+ CDBEnv *env;
+ std::string strFile;
+
+ /** Return whether this database handle is a dummy for testing.
+ * Only to be used at a low level, application should ideally not care
+ * about this.
+ */
+ bool IsDummy() { return env == nullptr; }
+};
+
/** RAII class that provides access to a Berkeley database */
class CDB
@@ -99,19 +150,28 @@ protected:
DbTxn* activeTxn;
bool fReadOnly;
bool fFlushOnClose;
+ CDBEnv *env;
- explicit CDB(const std::string& strFilename, const char* pszMode = "r+", bool fFlushOnCloseIn=true);
+public:
+ explicit CDB(CWalletDBWrapper& dbw, const char* pszMode = "r+", bool fFlushOnCloseIn=true);
~CDB() { Close(); }
-public:
+ CDB(const CDB&) = delete;
+ CDB& operator=(const CDB&) = delete;
+
void Flush();
void Close();
+ static bool Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& out_backup_filename);
-private:
- CDB(const CDB&);
- void operator=(const CDB&);
+ /* flush the wallet passively (TRY_LOCK)
+ ideal to be called periodically */
+ static bool PeriodicFlush(CWalletDBWrapper& dbw);
+ /* verifies the database environment */
+ static bool VerifyEnvironment(const std::string& walletFile, const fs::path& dataDir, std::string& errorStr);
+ /* verifies the database file */
+ static bool VerifyDatabaseFile(const std::string& walletFile, const fs::path& dataDir, std::string& warningStr, std::string& errorStr, CDBEnv::recoverFunc_type recoverFunc);
-protected:
+public:
template <typename K, typename T>
bool Read(const K& key, T& value)
{
@@ -128,29 +188,30 @@ protected:
Dbt datValue;
datValue.set_flags(DB_DBT_MALLOC);
int ret = pdb->get(activeTxn, &datKey, &datValue, 0);
- memset(datKey.get_data(), 0, datKey.get_size());
- if (datValue.get_data() == NULL)
- return false;
-
- // Unserialize value
- try {
- CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
- ssValue >> value;
- } catch (const std::exception&) {
- return false;
+ memory_cleanse(datKey.get_data(), datKey.get_size());
+ bool success = false;
+ if (datValue.get_data() != nullptr) {
+ // Unserialize value
+ try {
+ CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
+ ssValue >> value;
+ success = true;
+ } catch (const std::exception&) {
+ // In this case success remains 'false'
+ }
+
+ // Clear and free memory
+ memory_cleanse(datValue.get_data(), datValue.get_size());
+ free(datValue.get_data());
}
-
- // Clear and free memory
- memset(datValue.get_data(), 0, datValue.get_size());
- free(datValue.get_data());
- return (ret == 0);
+ return ret == 0 && success;
}
template <typename K, typename T>
bool Write(const K& key, const T& value, bool fOverwrite = true)
{
if (!pdb)
- return false;
+ return true;
if (fReadOnly)
assert(!"Write called on database in read-only mode");
@@ -170,8 +231,8 @@ protected:
int ret = pdb->put(activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
// Clear memory in case it was a private key
- memset(datKey.get_data(), 0, datKey.get_size());
- memset(datValue.get_data(), 0, datValue.get_size());
+ memory_cleanse(datKey.get_data(), datKey.get_size());
+ memory_cleanse(datValue.get_data(), datValue.get_size());
return (ret == 0);
}
@@ -193,7 +254,7 @@ protected:
int ret = pdb->del(activeTxn, &datKey, 0);
// Clear memory
- memset(datKey.get_data(), 0, datKey.get_size());
+ memory_cleanse(datKey.get_data(), datKey.get_size());
return (ret == 0 || ret == DB_NOTFOUND);
}
@@ -213,18 +274,18 @@ protected:
int ret = pdb->exists(activeTxn, &datKey, 0);
// Clear memory
- memset(datKey.get_data(), 0, datKey.get_size());
+ memory_cleanse(datKey.get_data(), datKey.get_size());
return (ret == 0);
}
Dbc* GetCursor()
{
if (!pdb)
- return NULL;
- Dbc* pcursor = NULL;
- int ret = pdb->cursor(NULL, &pcursor, 0);
+ return nullptr;
+ Dbc* pcursor = nullptr;
+ int ret = pdb->cursor(nullptr, &pcursor, 0);
if (ret != 0)
- return NULL;
+ return nullptr;
return pcursor;
}
@@ -244,7 +305,7 @@ protected:
int ret = pcursor->get(&datKey, &datValue, fFlags);
if (ret != 0)
return ret;
- else if (datKey.get_data() == NULL || datValue.get_data() == NULL)
+ else if (datKey.get_data() == nullptr || datValue.get_data() == nullptr)
return 99999;
// Convert to streams
@@ -256,8 +317,8 @@ protected:
ssValue.write((char*)datValue.get_data(), datValue.get_size());
// Clear and free memory
- memset(datKey.get_data(), 0, datKey.get_size());
- memset(datValue.get_data(), 0, datValue.get_size());
+ memory_cleanse(datKey.get_data(), datKey.get_size());
+ memory_cleanse(datValue.get_data(), datValue.get_size());
free(datKey.get_data());
free(datValue.get_data());
return 0;
@@ -280,7 +341,7 @@ public:
if (!pdb || !activeTxn)
return false;
int ret = activeTxn->commit(0);
- activeTxn = NULL;
+ activeTxn = nullptr;
return (ret == 0);
}
@@ -289,7 +350,7 @@ public:
if (!pdb || !activeTxn)
return false;
int ret = activeTxn->abort();
- activeTxn = NULL;
+ activeTxn = nullptr;
return (ret == 0);
}
@@ -304,7 +365,7 @@ public:
return Write(std::string("version"), nVersion);
}
- bool static Rewrite(const std::string& strFile, const char* pszSkip = NULL);
+ bool static Rewrite(CWalletDBWrapper& dbw, const char* pszSkip = nullptr);
};
#endif // BITCOIN_WALLET_DB_H
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
new file mode 100644
index 0000000000..6abd060714
--- /dev/null
+++ b/src/wallet/feebumper.cpp
@@ -0,0 +1,291 @@
+// Copyright (c) 2017 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 "wallet/coincontrol.h"
+#include "wallet/feebumper.h"
+#include "wallet/fees.h"
+#include "wallet/wallet.h"
+#include "policy/fees.h"
+#include "policy/policy.h"
+#include "policy/rbf.h"
+#include "validation.h" //for mempool access
+#include "txmempool.h"
+#include "utilmoneystr.h"
+#include "util.h"
+#include "net.h"
+
+// Calculate the size of the transaction assuming all signatures are max size
+// Use DummySignatureCreator, which inserts 72 byte signatures everywhere.
+// TODO: re-use this in CWallet::CreateTransaction (right now
+// CreateTransaction uses the constructed dummy-signed tx to do a priority
+// calculation, but we should be able to refactor after priority is removed).
+// NOTE: this requires that all inputs must be in mapWallet (eg the tx should
+// be IsAllFromMe).
+int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *pWallet)
+{
+ CMutableTransaction txNew(tx);
+ std::vector<CInputCoin> vCoins;
+ // Look up the inputs. We should have already checked that this transaction
+ // IsAllFromMe(ISMINE_SPENDABLE), so every input should already be in our
+ // wallet, with a valid index into the vout array.
+ for (auto& input : tx.vin) {
+ const auto mi = pWallet->mapWallet.find(input.prevout.hash);
+ assert(mi != pWallet->mapWallet.end() && input.prevout.n < mi->second.tx->vout.size());
+ vCoins.emplace_back(CInputCoin(&(mi->second), input.prevout.n));
+ }
+ if (!pWallet->DummySignTx(txNew, vCoins)) {
+ // This should never happen, because IsAllFromMe(ISMINE_SPENDABLE)
+ // implies that we can sign for every input.
+ return -1;
+ }
+ return GetVirtualTransactionSize(txNew);
+}
+
+bool CFeeBumper::preconditionChecks(const CWallet *pWallet, const CWalletTx& wtx) {
+ if (pWallet->HasWalletSpend(wtx.GetHash())) {
+ vErrors.push_back("Transaction has descendants in the wallet");
+ currentResult = BumpFeeResult::INVALID_PARAMETER;
+ return false;
+ }
+
+ {
+ LOCK(mempool.cs);
+ auto it_mp = mempool.mapTx.find(wtx.GetHash());
+ if (it_mp != mempool.mapTx.end() && it_mp->GetCountWithDescendants() > 1) {
+ vErrors.push_back("Transaction has descendants in the mempool");
+ currentResult = BumpFeeResult::INVALID_PARAMETER;
+ return false;
+ }
+ }
+
+ if (wtx.GetDepthInMainChain() != 0) {
+ vErrors.push_back("Transaction has been mined, or is conflicted with a mined transaction");
+ currentResult = BumpFeeResult::WALLET_ERROR;
+ return false;
+ }
+ return true;
+}
+
+CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, const CCoinControl& coin_control, CAmount totalFee)
+ :
+ txid(std::move(txidIn)),
+ nOldFee(0),
+ nNewFee(0)
+{
+ vErrors.clear();
+ bumpedTxid.SetNull();
+ AssertLockHeld(pWallet->cs_wallet);
+ auto it = pWallet->mapWallet.find(txid);
+ if (it == pWallet->mapWallet.end()) {
+ vErrors.push_back("Invalid or non-wallet transaction id");
+ currentResult = BumpFeeResult::INVALID_ADDRESS_OR_KEY;
+ return;
+ }
+ const CWalletTx& wtx = it->second;
+
+ if (!preconditionChecks(pWallet, wtx)) {
+ return;
+ }
+
+ if (!SignalsOptInRBF(wtx)) {
+ vErrors.push_back("Transaction is not BIP 125 replaceable");
+ currentResult = BumpFeeResult::WALLET_ERROR;
+ return;
+ }
+
+ if (wtx.mapValue.count("replaced_by_txid")) {
+ vErrors.push_back(strprintf("Cannot bump transaction %s which was already bumped by transaction %s", txid.ToString(), wtx.mapValue.at("replaced_by_txid")));
+ currentResult = BumpFeeResult::WALLET_ERROR;
+ return;
+ }
+
+ // check that original tx consists entirely of our inputs
+ // if not, we can't bump the fee, because the wallet has no way of knowing the value of the other inputs (thus the fee)
+ if (!pWallet->IsAllFromMe(wtx, ISMINE_SPENDABLE)) {
+ vErrors.push_back("Transaction contains inputs that don't belong to this wallet");
+ currentResult = BumpFeeResult::WALLET_ERROR;
+ return;
+ }
+
+ // figure out which output was change
+ // if there was no change output or multiple change outputs, fail
+ int nOutput = -1;
+ for (size_t i = 0; i < wtx.tx->vout.size(); ++i) {
+ if (pWallet->IsChange(wtx.tx->vout[i])) {
+ if (nOutput != -1) {
+ vErrors.push_back("Transaction has multiple change outputs");
+ currentResult = BumpFeeResult::WALLET_ERROR;
+ return;
+ }
+ nOutput = i;
+ }
+ }
+ if (nOutput == -1) {
+ vErrors.push_back("Transaction does not have a change output");
+ currentResult = BumpFeeResult::WALLET_ERROR;
+ return;
+ }
+
+ // Calculate the expected size of the new transaction.
+ int64_t txSize = GetVirtualTransactionSize(*(wtx.tx));
+ const int64_t maxNewTxSize = CalculateMaximumSignedTxSize(*wtx.tx, pWallet);
+ if (maxNewTxSize < 0) {
+ vErrors.push_back("Transaction contains inputs that cannot be signed");
+ currentResult = BumpFeeResult::INVALID_ADDRESS_OR_KEY;
+ return;
+ }
+
+ // calculate the old fee and fee-rate
+ nOldFee = wtx.GetDebit(ISMINE_SPENDABLE) - wtx.tx->GetValueOut();
+ CFeeRate nOldFeeRate(nOldFee, txSize);
+ CFeeRate nNewFeeRate;
+ // The wallet uses a conservative WALLET_INCREMENTAL_RELAY_FEE value to
+ // future proof against changes to network wide policy for incremental relay
+ // fee that our node may not be aware of.
+ CFeeRate walletIncrementalRelayFee = CFeeRate(WALLET_INCREMENTAL_RELAY_FEE);
+ if (::incrementalRelayFee > walletIncrementalRelayFee) {
+ walletIncrementalRelayFee = ::incrementalRelayFee;
+ }
+
+ if (totalFee > 0) {
+ CAmount minTotalFee = nOldFeeRate.GetFee(maxNewTxSize) + ::incrementalRelayFee.GetFee(maxNewTxSize);
+ if (totalFee < minTotalFee) {
+ vErrors.push_back(strprintf("Insufficient totalFee, must be at least %s (oldFee %s + incrementalFee %s)",
+ FormatMoney(minTotalFee), FormatMoney(nOldFeeRate.GetFee(maxNewTxSize)), FormatMoney(::incrementalRelayFee.GetFee(maxNewTxSize))));
+ currentResult = BumpFeeResult::INVALID_PARAMETER;
+ return;
+ }
+ CAmount requiredFee = GetRequiredFee(maxNewTxSize);
+ if (totalFee < requiredFee) {
+ vErrors.push_back(strprintf("Insufficient totalFee (cannot be less than required fee %s)",
+ FormatMoney(requiredFee)));
+ currentResult = BumpFeeResult::INVALID_PARAMETER;
+ return;
+ }
+ nNewFee = totalFee;
+ nNewFeeRate = CFeeRate(totalFee, maxNewTxSize);
+ } else {
+ nNewFee = GetMinimumFee(maxNewTxSize, coin_control, mempool, ::feeEstimator, nullptr /* FeeCalculation */);
+ nNewFeeRate = CFeeRate(nNewFee, maxNewTxSize);
+
+ // New fee rate must be at least old rate + minimum incremental relay rate
+ // walletIncrementalRelayFee.GetFeePerK() should be exact, because it's initialized
+ // in that unit (fee per kb).
+ // However, nOldFeeRate is a calculated value from the tx fee/size, so
+ // add 1 satoshi to the result, because it may have been rounded down.
+ if (nNewFeeRate.GetFeePerK() < nOldFeeRate.GetFeePerK() + 1 + walletIncrementalRelayFee.GetFeePerK()) {
+ nNewFeeRate = CFeeRate(nOldFeeRate.GetFeePerK() + 1 + walletIncrementalRelayFee.GetFeePerK());
+ nNewFee = nNewFeeRate.GetFee(maxNewTxSize);
+ }
+ }
+
+ // Check that in all cases the new fee doesn't violate maxTxFee
+ if (nNewFee > maxTxFee) {
+ vErrors.push_back(strprintf("Specified or calculated fee %s is too high (cannot be higher than maxTxFee %s)",
+ FormatMoney(nNewFee), FormatMoney(maxTxFee)));
+ currentResult = BumpFeeResult::WALLET_ERROR;
+ return;
+ }
+
+ // check that fee rate is higher than mempool's minimum fee
+ // (no point in bumping fee if we know that the new tx won't be accepted to the mempool)
+ // This may occur if the user set TotalFee or paytxfee too low, if fallbackfee is too low, or, perhaps,
+ // in a rare situation where the mempool minimum fee increased significantly since the fee estimation just a
+ // moment earlier. In this case, we report an error to the user, who may use totalFee to make an adjustment.
+ CFeeRate minMempoolFeeRate = mempool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
+ if (nNewFeeRate.GetFeePerK() < minMempoolFeeRate.GetFeePerK()) {
+ vErrors.push_back(strprintf("New fee rate (%s) is less than the minimum fee rate (%s) to get into the mempool. totalFee value should to be at least %s or settxfee value should be at least %s to add transaction.", FormatMoney(nNewFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFee(maxNewTxSize)), FormatMoney(minMempoolFeeRate.GetFeePerK())));
+ currentResult = BumpFeeResult::WALLET_ERROR;
+ return;
+ }
+
+ // Now modify the output to increase the fee.
+ // If the output is not large enough to pay the fee, fail.
+ CAmount nDelta = nNewFee - nOldFee;
+ assert(nDelta > 0);
+ mtx = *wtx.tx;
+ CTxOut* poutput = &(mtx.vout[nOutput]);
+ if (poutput->nValue < nDelta) {
+ vErrors.push_back("Change output is too small to bump the fee");
+ currentResult = BumpFeeResult::WALLET_ERROR;
+ return;
+ }
+
+ // If the output would become dust, discard it (converting the dust to fee)
+ poutput->nValue -= nDelta;
+ if (poutput->nValue <= GetDustThreshold(*poutput, ::dustRelayFee)) {
+ LogPrint(BCLog::RPC, "Bumping fee and discarding dust output\n");
+ nNewFee += poutput->nValue;
+ mtx.vout.erase(mtx.vout.begin() + nOutput);
+ }
+
+ // Mark new tx not replaceable, if requested.
+ if (!coin_control.signalRbf) {
+ for (auto& input : mtx.vin) {
+ if (input.nSequence < 0xfffffffe) input.nSequence = 0xfffffffe;
+ }
+ }
+
+ currentResult = BumpFeeResult::OK;
+}
+
+bool CFeeBumper::signTransaction(CWallet *pWallet)
+{
+ return pWallet->SignTransaction(mtx);
+}
+
+bool CFeeBumper::commit(CWallet *pWallet)
+{
+ AssertLockHeld(pWallet->cs_wallet);
+ if (!vErrors.empty() || currentResult != BumpFeeResult::OK) {
+ return false;
+ }
+ auto it = txid.IsNull() ? pWallet->mapWallet.end() : pWallet->mapWallet.find(txid);
+ if (it == pWallet->mapWallet.end()) {
+ vErrors.push_back("Invalid or non-wallet transaction id");
+ currentResult = BumpFeeResult::MISC_ERROR;
+ return false;
+ }
+ CWalletTx& oldWtx = it->second;
+
+ // make sure the transaction still has no descendants and hasn't been mined in the meantime
+ if (!preconditionChecks(pWallet, oldWtx)) {
+ return false;
+ }
+
+ CWalletTx wtxBumped(pWallet, MakeTransactionRef(std::move(mtx)));
+ // commit/broadcast the tx
+ CReserveKey reservekey(pWallet);
+ wtxBumped.mapValue = oldWtx.mapValue;
+ wtxBumped.mapValue["replaces_txid"] = oldWtx.GetHash().ToString();
+ wtxBumped.vOrderForm = oldWtx.vOrderForm;
+ wtxBumped.strFromAccount = oldWtx.strFromAccount;
+ wtxBumped.fTimeReceivedIsTxTime = true;
+ wtxBumped.fFromMe = true;
+ CValidationState state;
+ if (!pWallet->CommitTransaction(wtxBumped, reservekey, g_connman.get(), state)) {
+ // NOTE: CommitTransaction never returns false, so this should never happen.
+ vErrors.push_back(strprintf("Error: The transaction was rejected! Reason given: %s", state.GetRejectReason()));
+ return false;
+ }
+
+ bumpedTxid = wtxBumped.GetHash();
+ if (state.IsInvalid()) {
+ // This can happen if the mempool rejected the transaction. Report
+ // what happened in the "errors" response.
+ vErrors.push_back(strprintf("Error: The transaction was rejected: %s", FormatStateMessage(state)));
+ }
+
+ // mark the original tx as bumped
+ if (!pWallet->MarkReplaced(oldWtx.GetHash(), wtxBumped.GetHash())) {
+ // TODO: see if JSON-RPC has a standard way of returning a response
+ // along with an exception. It would be good to return information about
+ // wtxBumped to the caller even if marking the original transaction
+ // replaced does not succeed for some reason.
+ vErrors.push_back("Error: Created new bumpfee transaction but could not mark the original transaction as replaced.");
+ }
+ return true;
+}
+
diff --git a/src/wallet/feebumper.h b/src/wallet/feebumper.h
new file mode 100644
index 0000000000..3d64e53c15
--- /dev/null
+++ b/src/wallet/feebumper.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2017 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_WALLET_FEEBUMPER_H
+#define BITCOIN_WALLET_FEEBUMPER_H
+
+#include <primitives/transaction.h>
+
+class CWallet;
+class CWalletTx;
+class uint256;
+class CCoinControl;
+enum class FeeEstimateMode;
+
+enum class BumpFeeResult
+{
+ OK,
+ INVALID_ADDRESS_OR_KEY,
+ INVALID_REQUEST,
+ INVALID_PARAMETER,
+ WALLET_ERROR,
+ MISC_ERROR,
+};
+
+class CFeeBumper
+{
+public:
+ CFeeBumper(const CWallet *pWalletIn, const uint256 txidIn, const CCoinControl& coin_control, CAmount totalFee);
+ BumpFeeResult getResult() const { return currentResult; }
+ const std::vector<std::string>& getErrors() const { return vErrors; }
+ CAmount getOldFee() const { return nOldFee; }
+ CAmount getNewFee() const { return nNewFee; }
+ uint256 getBumpedTxId() const { return bumpedTxid; }
+
+ /* signs the new transaction,
+ * returns false if the tx couldn't be found or if it was
+ * impossible to create the signature(s)
+ */
+ bool signTransaction(CWallet *pWallet);
+
+ /* commits the fee bump,
+ * returns true, in case of CWallet::CommitTransaction was successful
+ * but, eventually sets vErrors if the tx could not be added to the mempool (will try later)
+ * or if the old transaction could not be marked as replaced
+ */
+ bool commit(CWallet *pWalletNonConst);
+
+private:
+ bool preconditionChecks(const CWallet *pWallet, const CWalletTx& wtx);
+
+ const uint256 txid;
+ uint256 bumpedTxid;
+ CMutableTransaction mtx;
+ std::vector<std::string> vErrors;
+ BumpFeeResult currentResult;
+ CAmount nOldFee;
+ CAmount nNewFee;
+};
+
+#endif // BITCOIN_WALLET_FEEBUMPER_H
diff --git a/src/wallet/fees.cpp b/src/wallet/fees.cpp
new file mode 100644
index 0000000000..76eeeeda05
--- /dev/null
+++ b/src/wallet/fees.cpp
@@ -0,0 +1,89 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2017 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 "wallet/fees.h"
+
+#include "policy/policy.h"
+#include "txmempool.h"
+#include "util.h"
+#include "validation.h"
+#include "wallet/coincontrol.h"
+#include "wallet/wallet.h"
+
+
+CAmount GetRequiredFee(unsigned int nTxBytes)
+{
+ return std::max(CWallet::minTxFee.GetFee(nTxBytes), ::minRelayTxFee.GetFee(nTxBytes));
+}
+
+
+CAmount GetMinimumFee(unsigned int nTxBytes, const CCoinControl& coin_control, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc)
+{
+ /* User control of how to calculate fee uses the following parameter precedence:
+ 1. coin_control.m_feerate
+ 2. coin_control.m_confirm_target
+ 3. payTxFee (user-set global variable)
+ 4. nTxConfirmTarget (user-set global variable)
+ The first parameter that is set is used.
+ */
+ CAmount fee_needed;
+ if (coin_control.m_feerate) { // 1.
+ fee_needed = coin_control.m_feerate->GetFee(nTxBytes);
+ if (feeCalc) feeCalc->reason = FeeReason::PAYTXFEE;
+ // Allow to override automatic min/max check over coin control instance
+ if (coin_control.fOverrideFeeRate) return fee_needed;
+ }
+ else if (!coin_control.m_confirm_target && ::payTxFee != CFeeRate(0)) { // 3. TODO: remove magic value of 0 for global payTxFee
+ fee_needed = ::payTxFee.GetFee(nTxBytes);
+ if (feeCalc) feeCalc->reason = FeeReason::PAYTXFEE;
+ }
+ else { // 2. or 4.
+ // We will use smart fee estimation
+ unsigned int target = coin_control.m_confirm_target ? *coin_control.m_confirm_target : ::nTxConfirmTarget;
+ // By default estimates are economical iff we are signaling opt-in-RBF
+ bool conservative_estimate = !coin_control.signalRbf;
+ // Allow to override the default fee estimate mode over the CoinControl instance
+ if (coin_control.m_fee_mode == FeeEstimateMode::CONSERVATIVE) conservative_estimate = true;
+ else if (coin_control.m_fee_mode == FeeEstimateMode::ECONOMICAL) conservative_estimate = false;
+
+ fee_needed = estimator.estimateSmartFee(target, feeCalc, conservative_estimate).GetFee(nTxBytes);
+ if (fee_needed == 0) {
+ // if we don't have enough data for estimateSmartFee, then use fallbackFee
+ fee_needed = CWallet::fallbackFee.GetFee(nTxBytes);
+ if (feeCalc) feeCalc->reason = FeeReason::FALLBACK;
+ }
+ // Obey mempool min fee when using smart fee estimation
+ CAmount min_mempool_fee = pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nTxBytes);
+ if (fee_needed < min_mempool_fee) {
+ fee_needed = min_mempool_fee;
+ if (feeCalc) feeCalc->reason = FeeReason::MEMPOOL_MIN;
+ }
+ }
+
+ // prevent user from paying a fee below minRelayTxFee or minTxFee
+ CAmount required_fee = GetRequiredFee(nTxBytes);
+ if (required_fee > fee_needed) {
+ fee_needed = required_fee;
+ if (feeCalc) feeCalc->reason = FeeReason::REQUIRED;
+ }
+ // But always obey the maximum
+ if (fee_needed > maxTxFee) {
+ fee_needed = maxTxFee;
+ if (feeCalc) feeCalc->reason = FeeReason::MAXTXFEE;
+ }
+ return fee_needed;
+}
+
+
+CFeeRate GetDiscardRate(const CBlockPolicyEstimator& estimator)
+{
+ unsigned int highest_target = estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
+ CFeeRate discard_rate = estimator.estimateSmartFee(highest_target, nullptr /* FeeCalculation */, false /* conservative */);
+ // Don't let discard_rate be greater than longest possible fee estimate if we get a valid fee estimate
+ discard_rate = (discard_rate == CFeeRate(0)) ? CWallet::m_discard_rate : std::min(discard_rate, CWallet::m_discard_rate);
+ // Discard rate must be at least dustRelayFee
+ discard_rate = std::max(discard_rate, ::dustRelayFee);
+ return discard_rate;
+}
diff --git a/src/wallet/fees.h b/src/wallet/fees.h
new file mode 100644
index 0000000000..7b8a7dc868
--- /dev/null
+++ b/src/wallet/fees.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2017 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_WALLET_FEES_H
+#define BITCOIN_WALLET_FEES_H
+
+#include "amount.h"
+
+class CBlockPolicyEstimator;
+class CCoinControl;
+class CFeeRate;
+class CTxMemPool;
+struct FeeCalculation;
+
+/**
+ * Return the minimum required fee taking into account the
+ * floating relay fee and user set minimum transaction fee
+ */
+CAmount GetRequiredFee(unsigned int nTxBytes);
+
+/**
+ * Estimate the minimum fee considering user set parameters
+ * and the required fee
+ */
+CAmount GetMinimumFee(unsigned int nTxBytes, const CCoinControl& coin_control, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc);
+
+/**
+ * Return the maximum feerate for discarding change.
+ */
+CFeeRate GetDiscardRate(const CBlockPolicyEstimator& estimator);
+
+#endif // BITCOIN_WALLET_FEES_H
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
new file mode 100644
index 0000000000..c984df1df8
--- /dev/null
+++ b/src/wallet/init.cpp
@@ -0,0 +1,279 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2017 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 "wallet/init.h"
+
+#include "net.h"
+#include "util.h"
+#include "utilmoneystr.h"
+#include "validation.h"
+#include "wallet/wallet.h"
+#include "wallet/rpcwallet.h"
+
+std::string GetWalletHelpString(bool showDebug)
+{
+ std::string 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)"), DEFAULT_KEYPOOL_SIZE));
+ strUsage += HelpMessageOpt("-fallbackfee=<amt>", strprintf(_("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)"),
+ CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)));
+ strUsage += HelpMessageOpt("-discardfee=<amt>", strprintf(_("The fee rate (in %s/kB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). "
+ "Note: An output is discarded if it is dust at this rate, but we will always discard up to the dust relay fee and a discard fee above that is limited by the fee estimate for the longest target"),
+ CURRENCY_UNIT, FormatMoney(DEFAULT_DISCARD_FEE)));
+ strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)"),
+ CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE)));
+ 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 on startup"));
+ strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE));
+ 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("-walletrbf", strprintf(_("Send transactions with full-RBF opt-in enabled (default: %u)"), DEFAULT_WALLET_RBF));
+ strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format on startup"));
+ strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT));
+ strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), DEFAULT_WALLETBROADCAST));
+ 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)"));
+
+ if (showDebug)
+ {
+ strUsage += HelpMessageGroup(_("Wallet debugging/testing options:"));
+
+ strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf("Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE));
+ strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET));
+ strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB));
+ strUsage += HelpMessageOpt("-walletrejectlongchains", strprintf(_("Wallet will not create transactions that violate mempool chain limits (default: %u)"), DEFAULT_WALLET_REJECT_LONG_CHAINS));
+ }
+
+ return strUsage;
+}
+
+bool WalletParameterInteraction()
+{
+ gArgs.SoftSetArg("-wallet", DEFAULT_WALLET_DAT);
+ const bool is_multiwallet = gArgs.GetArgs("-wallet").size() > 1;
+
+ if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET))
+ return true;
+
+ if (gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && gArgs.SoftSetBoolArg("-walletbroadcast", false)) {
+ LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__);
+ }
+
+ if (gArgs.GetBoolArg("-salvagewallet", false)) {
+ if (is_multiwallet) {
+ return InitError(strprintf("%s is only allowed with a single wallet file", "-salvagewallet"));
+ }
+ // Rewrite just private keys: rescan to find transactions
+ if (gArgs.SoftSetBoolArg("-rescan", true)) {
+ LogPrintf("%s: parameter interaction: -salvagewallet=1 -> setting -rescan=1\n", __func__);
+ }
+ }
+
+ int zapwallettxes = gArgs.GetArg("-zapwallettxes", 0);
+ // -zapwallettxes implies dropping the mempool on startup
+ if (zapwallettxes != 0 && gArgs.SoftSetBoolArg("-persistmempool", false)) {
+ LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -persistmempool=0\n", __func__, zapwallettxes);
+ }
+
+ // -zapwallettxes implies a rescan
+ if (zapwallettxes != 0) {
+ if (is_multiwallet) {
+ return InitError(strprintf("%s is only allowed with a single wallet file", "-zapwallettxes"));
+ }
+ if (gArgs.SoftSetBoolArg("-rescan", true)) {
+ LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -rescan=1\n", __func__, zapwallettxes);
+ }
+ }
+
+ if (is_multiwallet) {
+ if (gArgs.GetBoolArg("-upgradewallet", false)) {
+ return InitError(strprintf("%s is only allowed with a single wallet file", "-upgradewallet"));
+ }
+ }
+
+ if (gArgs.GetBoolArg("-sysperms", false))
+ return InitError("-sysperms is not allowed in combination with enabled wallet functionality");
+ if (gArgs.GetArg("-prune", 0) && gArgs.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."));
+
+ if (::minRelayTxFee.GetFeePerK() > HIGH_TX_FEE_PER_KB)
+ InitWarning(AmountHighWarn("-minrelaytxfee") + " " +
+ _("The wallet will avoid paying less than the minimum relay fee."));
+
+ if (gArgs.IsArgSet("-mintxfee"))
+ {
+ CAmount n = 0;
+ if (!ParseMoney(gArgs.GetArg("-mintxfee", ""), n) || 0 == n)
+ return InitError(AmountErrMsg("mintxfee", gArgs.GetArg("-mintxfee", "")));
+ if (n > HIGH_TX_FEE_PER_KB)
+ InitWarning(AmountHighWarn("-mintxfee") + " " +
+ _("This is the minimum transaction fee you pay on every transaction."));
+ CWallet::minTxFee = CFeeRate(n);
+ }
+ if (gArgs.IsArgSet("-fallbackfee"))
+ {
+ CAmount nFeePerK = 0;
+ if (!ParseMoney(gArgs.GetArg("-fallbackfee", ""), nFeePerK))
+ return InitError(strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), gArgs.GetArg("-fallbackfee", "")));
+ if (nFeePerK > HIGH_TX_FEE_PER_KB)
+ InitWarning(AmountHighWarn("-fallbackfee") + " " +
+ _("This is the transaction fee you may pay when fee estimates are not available."));
+ CWallet::fallbackFee = CFeeRate(nFeePerK);
+ }
+ if (gArgs.IsArgSet("-discardfee"))
+ {
+ CAmount nFeePerK = 0;
+ if (!ParseMoney(gArgs.GetArg("-discardfee", ""), nFeePerK))
+ return InitError(strprintf(_("Invalid amount for -discardfee=<amount>: '%s'"), gArgs.GetArg("-discardfee", "")));
+ if (nFeePerK > HIGH_TX_FEE_PER_KB)
+ InitWarning(AmountHighWarn("-discardfee") + " " +
+ _("This is the transaction fee you may discard if change is smaller than dust at this level"));
+ CWallet::m_discard_rate = CFeeRate(nFeePerK);
+ }
+ if (gArgs.IsArgSet("-paytxfee"))
+ {
+ CAmount nFeePerK = 0;
+ if (!ParseMoney(gArgs.GetArg("-paytxfee", ""), nFeePerK))
+ return InitError(AmountErrMsg("paytxfee", gArgs.GetArg("-paytxfee", "")));
+ if (nFeePerK > HIGH_TX_FEE_PER_KB)
+ InitWarning(AmountHighWarn("-paytxfee") + " " +
+ _("This is the transaction fee you will pay if you send a transaction."));
+
+ payTxFee = CFeeRate(nFeePerK, 1000);
+ if (payTxFee < ::minRelayTxFee)
+ {
+ return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
+ gArgs.GetArg("-paytxfee", ""), ::minRelayTxFee.ToString()));
+ }
+ }
+ if (gArgs.IsArgSet("-maxtxfee"))
+ {
+ CAmount nMaxFee = 0;
+ if (!ParseMoney(gArgs.GetArg("-maxtxfee", ""), nMaxFee))
+ return InitError(AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", "")));
+ if (nMaxFee > HIGH_MAX_TX_FEE)
+ InitWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
+ maxTxFee = nMaxFee;
+ if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee)
+ {
+ return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
+ gArgs.GetArg("-maxtxfee", ""), ::minRelayTxFee.ToString()));
+ }
+ }
+ nTxConfirmTarget = gArgs.GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);
+ bSpendZeroConfChange = gArgs.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
+ fWalletRbf = gArgs.GetBoolArg("-walletrbf", DEFAULT_WALLET_RBF);
+
+ return true;
+}
+
+void RegisterWalletRPC(CRPCTable &t)
+{
+ if (gArgs.GetBoolArg("-disablewallet", false)) return;
+
+ RegisterWalletRPCCommands(t);
+}
+
+bool VerifyWallets()
+{
+ if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET))
+ return true;
+
+ uiInterface.InitMessage(_("Verifying wallet(s)..."));
+
+ // Keep track of each wallet absolute path to detect duplicates.
+ std::set<fs::path> wallet_paths;
+
+ for (const std::string& walletFile : gArgs.GetArgs("-wallet")) {
+ if (boost::filesystem::path(walletFile).filename() != walletFile) {
+ return InitError(strprintf(_("Error loading wallet %s. -wallet parameter must only specify a filename (not a path)."), walletFile));
+ }
+
+ if (SanitizeString(walletFile, SAFE_CHARS_FILENAME) != walletFile) {
+ return InitError(strprintf(_("Error loading wallet %s. Invalid characters in -wallet filename."), walletFile));
+ }
+
+ fs::path wallet_path = fs::absolute(walletFile, GetDataDir());
+
+ if (fs::exists(wallet_path) && (!fs::is_regular_file(wallet_path) || fs::is_symlink(wallet_path))) {
+ return InitError(strprintf(_("Error loading wallet %s. -wallet filename must be a regular file."), walletFile));
+ }
+
+ if (!wallet_paths.insert(wallet_path).second) {
+ return InitError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified."), walletFile));
+ }
+
+ std::string strError;
+ if (!CWalletDB::VerifyEnvironment(walletFile, GetDataDir().string(), strError)) {
+ return InitError(strError);
+ }
+
+ if (gArgs.GetBoolArg("-salvagewallet", false)) {
+ // Recover readable keypairs:
+ CWallet dummyWallet;
+ std::string backup_filename;
+ if (!CWalletDB::Recover(walletFile, (void *)&dummyWallet, CWalletDB::RecoverKeysOnlyFilter, backup_filename)) {
+ return false;
+ }
+ }
+
+ std::string strWarning;
+ bool dbV = CWalletDB::VerifyDatabaseFile(walletFile, GetDataDir().string(), strWarning, strError);
+ if (!strWarning.empty()) {
+ InitWarning(strWarning);
+ }
+ if (!dbV) {
+ InitError(strError);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool OpenWallets()
+{
+ if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
+ LogPrintf("Wallet disabled!\n");
+ return true;
+ }
+
+ for (const std::string& walletFile : gArgs.GetArgs("-wallet")) {
+ CWallet * const pwallet = CWallet::CreateWalletFromFile(walletFile);
+ if (!pwallet) {
+ return false;
+ }
+ vpwallets.push_back(pwallet);
+ }
+
+ return true;
+}
+
+void StartWallets(CScheduler& scheduler) {
+ for (CWalletRef pwallet : vpwallets) {
+ pwallet->postInitProcess(scheduler);
+ }
+}
+
+void FlushWallets() {
+ for (CWalletRef pwallet : vpwallets) {
+ pwallet->Flush(false);
+ }
+}
+
+void StopWallets() {
+ for (CWalletRef pwallet : vpwallets) {
+ pwallet->Flush(true);
+ }
+}
+
+void CloseWallets() {
+ for (CWalletRef pwallet : vpwallets) {
+ delete pwallet;
+ }
+ vpwallets.clear();
+}
diff --git a/src/wallet/init.h b/src/wallet/init.h
new file mode 100644
index 0000000000..0b3ee2dda2
--- /dev/null
+++ b/src/wallet/init.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2017 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_WALLET_INIT_H
+#define BITCOIN_WALLET_INIT_H
+
+#include <string>
+
+class CRPCTable;
+class CScheduler;
+
+//! Return the wallets help message.
+std::string GetWalletHelpString(bool showDebug);
+
+//! Wallets parameter interaction
+bool WalletParameterInteraction();
+
+//! Register wallet RPCs.
+void RegisterWalletRPC(CRPCTable &tableRPC);
+
+//! Responsible for reading and validating the -wallet arguments and verifying the wallet database.
+// This function will perform salvage on the wallet if requested, as long as only one wallet is
+// being loaded (WalletParameterInteraction forbids -salvagewallet, -zapwallettxes or -upgradewallet with multiwallet).
+bool VerifyWallets();
+
+//! Load wallet databases.
+bool OpenWallets();
+
+//! Complete startup of wallets.
+void StartWallets(CScheduler& scheduler);
+
+//! Flush all wallets in preparation for shutdown.
+void FlushWallets();
+
+//! Stop all wallets. Wallets will be flushed first.
+void StopWallets();
+
+//! Close all wallets.
+void CloseWallets();
+
+#endif // BITCOIN_WALLET_INIT_H
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 7d4ed70ed9..1123fd6dbb 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -4,6 +4,7 @@
#include "base58.h"
#include "chain.h"
+#include "rpc/safemode.h"
#include "rpc/server.h"
#include "init.h"
#include "validation.h"
@@ -16,6 +17,8 @@
#include "merkleblock.h"
#include "core_io.h"
+#include "rpcwallet.h"
+
#include <fstream>
#include <stdint.h>
@@ -24,13 +27,6 @@
#include <univalue.h>
-#include <boost/assign/list_of.hpp>
-#include <boost/foreach.hpp>
-
-using namespace std;
-
-void EnsureWalletIsUnlocked();
-bool EnsureWalletIsAvailable(bool avoidException);
std::string static EncodeDumpTime(int64_t nTime) {
return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime);
@@ -51,7 +47,7 @@ int64_t static DecodeDumpTime(const std::string &str) {
std::string static EncodeDumpString(const std::string &str) {
std::stringstream ret;
- BOOST_FOREACH(unsigned char c, str) {
+ for (unsigned char c : str) {
if (c <= 32 || c >= 128 || c == '%') {
ret << '%' << HexStr(&c, &c + 1);
} else {
@@ -77,11 +73,13 @@ std::string DecodeDumpString(const std::string &str) {
UniValue importprivkey(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
-
+ }
+
if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
- throw runtime_error(
+ throw std::runtime_error(
"importprivkey \"bitcoinprivkey\" ( \"label\" ) ( rescan )\n"
"\nAdds a private key (as returned by dumpprivkey) to your wallet.\n"
"\nArguments:\n"
@@ -96,23 +94,25 @@ UniValue importprivkey(const JSONRPCRequest& request)
+ HelpExampleCli("importprivkey", "\"mykey\"") +
"\nImport using a label and without rescan\n"
+ HelpExampleCli("importprivkey", "\"mykey\" \"testing\" false") +
+ "\nImport using default blank label and without rescan\n"
+ + HelpExampleCli("importprivkey", "\"mykey\" \"\" false") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- EnsureWalletIsUnlocked();
+ EnsureWalletIsUnlocked(pwallet);
- string strSecret = request.params[0].get_str();
- string strLabel = "";
- if (request.params.size() > 1)
+ std::string strSecret = request.params[0].get_str();
+ std::string strLabel = "";
+ if (!request.params[1].isNull())
strLabel = request.params[1].get_str();
// Whether to perform rescan after import
bool fRescan = true;
- if (request.params.size() > 2)
+ if (!request.params[2].isNull())
fRescan = request.params[2].get_bool();
if (fRescan && fPruneMode)
@@ -130,68 +130,101 @@ UniValue importprivkey(const JSONRPCRequest& request)
assert(key.VerifyPubKey(pubkey));
CKeyID vchAddress = pubkey.GetID();
{
- pwalletMain->MarkDirty();
- pwalletMain->SetAddressBook(vchAddress, strLabel, "receive");
+ pwallet->MarkDirty();
+ pwallet->SetAddressBook(vchAddress, strLabel, "receive");
// Don't throw error in case a key is already there
- if (pwalletMain->HaveKey(vchAddress))
+ if (pwallet->HaveKey(vchAddress)) {
return NullUniValue;
+ }
- pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1;
+ pwallet->mapKeyMetadata[vchAddress].nCreateTime = 1;
- if (!pwalletMain->AddKeyPubKey(key, pubkey))
+ if (!pwallet->AddKeyPubKey(key, pubkey)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
+ }
// whenever a key is imported, we need to scan the whole chain
- pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value'
+ pwallet->UpdateTimeFirstKey(1);
if (fRescan) {
- pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true);
+ pwallet->RescanFromTime(TIMESTAMP_MIN, true /* update */);
}
}
return NullUniValue;
}
-void ImportAddress(const CBitcoinAddress& address, const string& strLabel);
-void ImportScript(const CScript& script, const string& strLabel, bool isRedeemScript)
+UniValue abortrescan(const JSONRPCRequest& request)
+{
+ CWallet* const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
+ return NullUniValue;
+ }
+
+ if (request.fHelp || request.params.size() > 0)
+ throw std::runtime_error(
+ "abortrescan\n"
+ "\nStops current wallet rescan triggered e.g. by an importprivkey call.\n"
+ "\nExamples:\n"
+ "\nImport a private key\n"
+ + HelpExampleCli("importprivkey", "\"mykey\"") +
+ "\nAbort the running wallet rescan\n"
+ + HelpExampleCli("abortrescan", "") +
+ "\nAs a JSON-RPC call\n"
+ + HelpExampleRpc("abortrescan", "")
+ );
+
+ ObserveSafeMode();
+ if (!pwallet->IsScanning() || pwallet->IsAbortingRescan()) return false;
+ pwallet->AbortRescan();
+ return true;
+}
+
+void ImportAddress(CWallet*, const CTxDestination& dest, const std::string& strLabel);
+void ImportScript(CWallet* const pwallet, const CScript& script, const std::string& strLabel, bool isRedeemScript)
{
- if (!isRedeemScript && ::IsMine(*pwalletMain, script) == ISMINE_SPENDABLE)
+ if (!isRedeemScript && ::IsMine(*pwallet, script) == ISMINE_SPENDABLE) {
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
+ }
- pwalletMain->MarkDirty();
+ pwallet->MarkDirty();
- if (!pwalletMain->HaveWatchOnly(script) && !pwalletMain->AddWatchOnly(script))
+ if (!pwallet->HaveWatchOnly(script) && !pwallet->AddWatchOnly(script, 0 /* nCreateTime */)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
+ }
if (isRedeemScript) {
- if (!pwalletMain->HaveCScript(script) && !pwalletMain->AddCScript(script))
+ if (!pwallet->HaveCScript(script) && !pwallet->AddCScript(script)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet");
- ImportAddress(CBitcoinAddress(CScriptID(script)), strLabel);
+ }
+ ImportAddress(pwallet, CScriptID(script), strLabel);
} else {
CTxDestination destination;
if (ExtractDestination(script, destination)) {
- pwalletMain->SetAddressBook(destination, strLabel, "receive");
+ pwallet->SetAddressBook(destination, strLabel, "receive");
}
}
}
-void ImportAddress(const CBitcoinAddress& address, const string& strLabel)
+void ImportAddress(CWallet* const pwallet, const CTxDestination& dest, const std::string& strLabel)
{
- CScript script = GetScriptForDestination(address.Get());
- ImportScript(script, strLabel, false);
+ CScript script = GetScriptForDestination(dest);
+ ImportScript(pwallet, script, strLabel, false);
// add to address book or update label
- if (address.IsValid())
- pwalletMain->SetAddressBook(address.Get(), strLabel, "receive");
+ if (IsValidDestination(dest))
+ pwallet->SetAddressBook(dest, strLabel, "receive");
}
UniValue importaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
-
+ }
+
if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
- throw runtime_error(
+ throw std::runtime_error(
"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"
@@ -213,13 +246,13 @@ UniValue importaddress(const JSONRPCRequest& request)
);
- string strLabel = "";
- if (request.params.size() > 1)
+ std::string strLabel = "";
+ if (!request.params[1].isNull())
strLabel = request.params[1].get_str();
// Whether to perform rescan after import
bool fRescan = true;
- if (request.params.size() > 2)
+ if (!request.params[2].isNull())
fRescan = request.params[2].get_bool();
if (fRescan && fPruneMode)
@@ -227,27 +260,28 @@ UniValue importaddress(const JSONRPCRequest& request)
// Whether to import a p2sh version, too
bool fP2SH = false;
- if (request.params.size() > 3)
+ if (!request.params[3].isNull())
fP2SH = request.params[3].get_bool();
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- CBitcoinAddress address(request.params[0].get_str());
- if (address.IsValid()) {
- if (fP2SH)
+ CTxDestination dest = DecodeDestination(request.params[0].get_str());
+ if (IsValidDestination(dest)) {
+ if (fP2SH) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot use the p2sh flag with an address - use a script instead");
- ImportAddress(address, strLabel);
+ }
+ ImportAddress(pwallet, dest, strLabel);
} else if (IsHex(request.params[0].get_str())) {
std::vector<unsigned char> data(ParseHex(request.params[0].get_str()));
- ImportScript(CScript(data.begin(), data.end()), strLabel, fP2SH);
+ ImportScript(pwallet, 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();
+ pwallet->RescanFromTime(TIMESTAMP_MIN, true /* update */);
+ pwallet->ReacceptWalletTransactions();
}
return NullUniValue;
@@ -255,11 +289,13 @@ UniValue importaddress(const JSONRPCRequest& request)
UniValue importprunedfunds(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() != 2)
- throw runtime_error(
+ throw std::runtime_error(
"importprunedfunds\n"
"\nImports funds without rescan. Corresponding address or script must previously be included in wallet. Aimed towards pruned wallets. The end-user is responsible to import additional transactions that subsequently spend the imported outputs or rescan after the point in the blockchain the transaction is included.\n"
"\nArguments:\n"
@@ -271,15 +307,15 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
if (!DecodeHexTx(tx, request.params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
uint256 hashTx = tx.GetHash();
- CWalletTx wtx(pwalletMain, MakeTransactionRef(std::move(tx)));
+ CWalletTx wtx(pwallet, MakeTransactionRef(std::move(tx)));
CDataStream ssMB(ParseHexV(request.params[1], "proof"), SER_NETWORK, PROTOCOL_VERSION);
CMerkleBlock merkleBlock;
ssMB >> merkleBlock;
//Search partial merkle tree in proof for our transaction and index in valid block
- vector<uint256> vMatch;
- vector<unsigned int> vIndex;
+ std::vector<uint256> vMatch;
+ std::vector<unsigned int> vIndex;
unsigned int txnIndex = 0;
if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) == merkleBlock.header.hashMerkleRoot) {
@@ -288,7 +324,7 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
if (!mapBlockIndex.count(merkleBlock.header.GetHash()) || !chainActive.Contains(mapBlockIndex[merkleBlock.header.GetHash()]))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
- vector<uint256>::const_iterator it;
+ std::vector<uint256>::const_iterator it;
if ((it = std::find(vMatch.begin(), vMatch.end(), hashTx))==vMatch.end()) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction given doesn't exist in proof");
}
@@ -302,10 +338,10 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
wtx.nIndex = txnIndex;
wtx.hashBlock = merkleBlock.header.GetHash();
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- if (pwalletMain->IsMine(wtx)) {
- pwalletMain->AddToWallet(wtx, false);
+ if (pwallet->IsMine(wtx)) {
+ pwallet->AddToWallet(wtx, false);
return NullUniValue;
}
@@ -314,35 +350,37 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
UniValue removeprunedfunds(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"removeprunedfunds \"txid\"\n"
- "\nDeletes the specified transaction from the wallet. Meant for use with pruned wallets and as a companion to importprunedfunds. This will effect wallet balances.\n"
+ "\nDeletes the specified transaction from the wallet. Meant for use with pruned wallets and as a companion to importprunedfunds. This will affect wallet balances.\n"
"\nArguments:\n"
"1. \"txid\" (string, required) The hex-encoded id of the transaction you are deleting\n"
"\nExamples:\n"
+ HelpExampleCli("removeprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"") +
"\nAs a JSON-RPC call\n"
- + HelpExampleRpc("removprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"")
+ + HelpExampleRpc("removeprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
uint256 hash;
hash.SetHex(request.params[0].get_str());
- vector<uint256> vHash;
+ std::vector<uint256> vHash;
vHash.push_back(hash);
- vector<uint256> vHashOut;
+ std::vector<uint256> vHashOut;
- if(pwalletMain->ZapSelectTx(vHash, vHashOut) != DB_LOAD_OK) {
- throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not properly delete the transaction.");
+ if (pwallet->ZapSelectTx(vHash, vHashOut) != DB_LOAD_OK) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Could not properly delete the transaction.");
}
if(vHashOut.empty()) {
- throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction does not exist in wallet.");
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction does not exist in wallet.");
}
return NullUniValue;
@@ -350,11 +388,13 @@ UniValue removeprunedfunds(const JSONRPCRequest& request)
UniValue importpubkey(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
- throw runtime_error(
+ throw std::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"
@@ -372,13 +412,13 @@ UniValue importpubkey(const JSONRPCRequest& request)
);
- string strLabel = "";
- if (request.params.size() > 1)
+ std::string strLabel = "";
+ if (!request.params[1].isNull())
strLabel = request.params[1].get_str();
// Whether to perform rescan after import
bool fRescan = true;
- if (request.params.size() > 2)
+ if (!request.params[2].isNull())
fRescan = request.params[2].get_bool();
if (fRescan && fPruneMode)
@@ -391,15 +431,15 @@ UniValue importpubkey(const JSONRPCRequest& request)
if (!pubKey.IsFullyValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey is not a valid public key");
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- ImportAddress(CBitcoinAddress(pubKey.GetID()), strLabel);
- ImportScript(GetScriptForRawPubKey(pubKey), strLabel, false);
+ ImportAddress(pwallet, pubKey.GetID(), strLabel);
+ ImportScript(pwallet, GetScriptForRawPubKey(pubKey), strLabel, false);
if (fRescan)
{
- pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true);
- pwalletMain->ReacceptWalletTransactions();
+ pwallet->RescanFromTime(TIMESTAMP_MIN, true /* update */);
+ pwallet->ReacceptWalletTransactions();
}
return NullUniValue;
@@ -408,11 +448,13 @@ UniValue importpubkey(const JSONRPCRequest& request)
UniValue importwallet(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
-
+ }
+
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"importwallet \"filename\"\n"
"\nImports keys from a wallet dump file (see dumpwallet).\n"
"\nArguments:\n"
@@ -429,11 +471,11 @@ UniValue importwallet(const JSONRPCRequest& request)
if (fPruneMode)
throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled in pruned mode");
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- EnsureWalletIsUnlocked();
+ EnsureWalletIsUnlocked(pwallet);
- ifstream file;
+ std::ifstream file;
file.open(request.params[0].get_str().c_str(), std::ios::in | std::ios::ate);
if (!file.is_open())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
@@ -445,9 +487,9 @@ UniValue importwallet(const JSONRPCRequest& request)
int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg());
file.seekg(0, file.beg);
- pwalletMain->ShowProgress(_("Importing..."), 0); // show progress dialog in GUI
+ pwallet->ShowProgress(_("Importing..."), 0); // show progress dialog in GUI
while (file.good()) {
- pwalletMain->ShowProgress("", std::max(1, std::min(99, (int)(((double)file.tellg() / (double)nFilesize) * 100))));
+ pwallet->ShowProgress("", std::max(1, std::min(99, (int)(((double)file.tellg() / (double)nFilesize) * 100))));
std::string line;
std::getline(file, line);
if (line.empty() || line[0] == '#')
@@ -464,8 +506,8 @@ UniValue importwallet(const JSONRPCRequest& request)
CPubKey pubkey = key.GetPubKey();
assert(key.VerifyPubKey(pubkey));
CKeyID keyid = pubkey.GetID();
- if (pwalletMain->HaveKey(keyid)) {
- LogPrintf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString());
+ if (pwallet->HaveKey(keyid)) {
+ LogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid));
continue;
}
int64_t nTime = DecodeDumpTime(vstr[1]);
@@ -483,29 +525,21 @@ UniValue importwallet(const JSONRPCRequest& request)
fLabel = true;
}
}
- LogPrintf("Importing %s...\n", CBitcoinAddress(keyid).ToString());
- if (!pwalletMain->AddKeyPubKey(key, pubkey)) {
+ LogPrintf("Importing %s...\n", EncodeDestination(keyid));
+ if (!pwallet->AddKeyPubKey(key, pubkey)) {
fGood = false;
continue;
}
- pwalletMain->mapKeyMetadata[keyid].nCreateTime = nTime;
+ pwallet->mapKeyMetadata[keyid].nCreateTime = nTime;
if (fLabel)
- pwalletMain->SetAddressBook(keyid, strLabel, "receive");
+ pwallet->SetAddressBook(keyid, strLabel, "receive");
nTimeBegin = std::min(nTimeBegin, nTime);
}
file.close();
- pwalletMain->ShowProgress("", 100); // hide progress dialog in GUI
-
- CBlockIndex *pindex = chainActive.Tip();
- while (pindex && pindex->pprev && pindex->GetBlockTime() > nTimeBegin - 7200)
- pindex = pindex->pprev;
-
- if (!pwalletMain->nTimeFirstKey || nTimeBegin < pwalletMain->nTimeFirstKey)
- pwalletMain->nTimeFirstKey = nTimeBegin;
-
- LogPrintf("Rescanning last %i blocks\n", chainActive.Height() - pindex->nHeight + 1);
- pwalletMain->ScanForWalletTransactions(pindex);
- pwalletMain->MarkDirty();
+ pwallet->ShowProgress("", 100); // hide progress dialog in GUI
+ pwallet->UpdateTimeFirstKey(nTimeBegin);
+ pwallet->RescanFromTime(nTimeBegin, false /* update */);
+ pwallet->MarkDirty();
if (!fGood)
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet");
@@ -515,11 +549,13 @@ UniValue importwallet(const JSONRPCRequest& request)
UniValue dumpprivkey(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
-
+ }
+
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"dumpprivkey \"address\"\n"
"\nReveals the private key corresponding to 'address'.\n"
"Then the importprivkey can be used with this output\n"
@@ -533,58 +569,80 @@ UniValue dumpprivkey(const JSONRPCRequest& request)
+ HelpExampleRpc("dumpprivkey", "\"myaddress\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- EnsureWalletIsUnlocked();
+ EnsureWalletIsUnlocked(pwallet);
- string strAddress = request.params[0].get_str();
- CBitcoinAddress address;
- if (!address.SetString(strAddress))
+ std::string strAddress = request.params[0].get_str();
+ CTxDestination dest = DecodeDestination(strAddress);
+ if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
- CKeyID keyID;
- if (!address.GetKeyID(keyID))
+ }
+ const CKeyID *keyID = boost::get<CKeyID>(&dest);
+ if (!keyID) {
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key");
+ }
CKey vchSecret;
- if (!pwalletMain->GetKey(keyID, vchSecret))
+ if (!pwallet->GetKey(*keyID, vchSecret)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
+ }
return CBitcoinSecret(vchSecret).ToString();
}
UniValue dumpwallet(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
-
+ }
+
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"dumpwallet \"filename\"\n"
- "\nDumps all wallet keys in a human-readable format.\n"
+ "\nDumps all wallet keys in a human-readable format to a server-side file. This does not allow overwriting existing files.\n"
"\nArguments:\n"
- "1. \"filename\" (string, required) The filename\n"
+ "1. \"filename\" (string, required) The filename with path (either absolute or relative to bitcoind)\n"
+ "\nResult:\n"
+ "{ (json object)\n"
+ " \"filename\" : { (string) The filename with full absolute path\n"
+ "}\n"
"\nExamples:\n"
+ HelpExampleCli("dumpwallet", "\"test\"")
+ HelpExampleRpc("dumpwallet", "\"test\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
+
+ EnsureWalletIsUnlocked(pwallet);
- EnsureWalletIsUnlocked();
+ boost::filesystem::path filepath = request.params[0].get_str();
+ filepath = boost::filesystem::absolute(filepath);
+
+ /* Prevent arbitrary files from being overwritten. There have been reports
+ * that users have overwritten wallet files this way:
+ * https://github.com/bitcoin/bitcoin/issues/9934
+ * It may also avoid other security issues.
+ */
+ if (boost::filesystem::exists(filepath)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, filepath.string() + " already exists. If you are sure this is what you want, move it out of the way first");
+ }
- ofstream file;
- file.open(request.params[0].get_str().c_str());
+ std::ofstream file;
+ file.open(filepath.string().c_str());
if (!file.is_open())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
- std::map<CKeyID, int64_t> mapKeyBirth;
- std::set<CKeyID> setKeyPool;
- pwalletMain->GetKeyBirthTimes(mapKeyBirth);
- pwalletMain->GetAllReserveKeys(setKeyPool);
+ std::map<CTxDestination, int64_t> mapKeyBirth;
+ const std::map<CKeyID, int64_t>& mapKeyPool = pwallet->GetAllReserveKeys();
+ pwallet->GetKeyBirthTimes(mapKeyBirth);
// sort time/key pairs
std::vector<std::pair<int64_t, CKeyID> > vKeyBirth;
- for (std::map<CKeyID, int64_t>::const_iterator it = mapKeyBirth.begin(); it != mapKeyBirth.end(); it++) {
- vKeyBirth.push_back(std::make_pair(it->second, it->first));
+ for (const auto& entry : mapKeyBirth) {
+ if (const CKeyID* keyID = boost::get<CKeyID>(&entry.first)) { // set and test
+ vKeyBirth.push_back(std::make_pair(entry.second, *keyID));
+ }
}
mapKeyBirth.clear();
std::sort(vKeyBirth.begin(), vKeyBirth.end());
@@ -597,12 +655,11 @@ UniValue dumpwallet(const JSONRPCRequest& request)
file << "\n";
// add the base58check encoded extended master if the wallet uses HD
- CKeyID masterKeyID = pwalletMain->GetHDChain().masterKeyID;
+ CKeyID masterKeyID = pwallet->GetHDChain().masterKeyID;
if (!masterKeyID.IsNull())
{
CKey key;
- if (pwalletMain->GetKey(masterKeyID, key))
- {
+ if (pwallet->GetKey(masterKeyID, key)) {
CExtKey masterKey;
masterKey.SetMaster(key.begin(), key.size());
@@ -615,32 +672,37 @@ UniValue dumpwallet(const JSONRPCRequest& request)
for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {
const CKeyID &keyid = it->second;
std::string strTime = EncodeDumpTime(it->first);
- std::string strAddr = CBitcoinAddress(keyid).ToString();
+ std::string strAddr = EncodeDestination(keyid);
CKey key;
- if (pwalletMain->GetKey(keyid, key)) {
+ if (pwallet->GetKey(keyid, key)) {
file << strprintf("%s %s ", CBitcoinSecret(key).ToString(), strTime);
- if (pwalletMain->mapAddressBook.count(keyid)) {
- file << strprintf("label=%s", EncodeDumpString(pwalletMain->mapAddressBook[keyid].name));
+ if (pwallet->mapAddressBook.count(keyid)) {
+ file << strprintf("label=%s", EncodeDumpString(pwallet->mapAddressBook[keyid].name));
} else if (keyid == masterKeyID) {
file << "hdmaster=1";
- } else if (setKeyPool.count(keyid)) {
+ } else if (mapKeyPool.count(keyid)) {
file << "reserve=1";
- } else if (pwalletMain->mapKeyMetadata[keyid].hdKeypath == "m") {
+ } else if (pwallet->mapKeyMetadata[keyid].hdKeypath == "m") {
file << "inactivehdmaster=1";
} else {
file << "change=1";
}
- file << strprintf(" # addr=%s%s\n", strAddr, (pwalletMain->mapKeyMetadata[keyid].hdKeypath.size() > 0 ? " hdkeypath="+pwalletMain->mapKeyMetadata[keyid].hdKeypath : ""));
+ file << strprintf(" # addr=%s%s\n", strAddr, (pwallet->mapKeyMetadata[keyid].hdKeypath.size() > 0 ? " hdkeypath="+pwallet->mapKeyMetadata[keyid].hdKeypath : ""));
}
}
file << "\n";
file << "# End of dump\n";
file.close();
- return NullUniValue;
+
+ UniValue reply(UniValue::VOBJ);
+ reply.push_back(Pair("filename", filepath.string()));
+
+ return reply;
}
-UniValue processImport(const UniValue& data) {
+UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int64_t timestamp)
+{
try {
bool success = false;
@@ -653,25 +715,27 @@ UniValue processImport(const UniValue& data) {
}
// Optional fields.
- const string& strRedeemScript = data.exists("redeemscript") ? data["redeemscript"].get_str() : "";
+ const std::string& strRedeemScript = data.exists("redeemscript") ? data["redeemscript"].get_str() : "";
const UniValue& pubKeys = data.exists("pubkeys") ? data["pubkeys"].get_array() : UniValue();
const UniValue& keys = data.exists("keys") ? data["keys"].get_array() : UniValue();
const bool& internal = data.exists("internal") ? data["internal"].get_bool() : false;
const bool& watchOnly = data.exists("watchonly") ? data["watchonly"].get_bool() : false;
- const string& label = data.exists("label") && !internal ? data["label"].get_str() : "";
- const int64_t& timestamp = data.exists("timestamp") && data["timestamp"].get_int64() > 1 ? data["timestamp"].get_int64() : 1;
+ const std::string& label = data.exists("label") && !internal ? data["label"].get_str() : "";
bool isScript = scriptPubKey.getType() == UniValue::VSTR;
bool isP2SH = strRedeemScript.length() > 0;
- const string& output = isScript ? scriptPubKey.get_str() : scriptPubKey["address"].get_str();
+ const std::string& output = isScript ? scriptPubKey.get_str() : scriptPubKey["address"].get_str();
// Parse the output.
CScript script;
- CBitcoinAddress address;
+ CTxDestination dest;
if (!isScript) {
- address = CBitcoinAddress(output);
- script = GetScriptForDestination(address.Get());
+ dest = DecodeDestination(output);
+ if (!IsValidDestination(dest)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
+ }
+ script = GetScriptForDestination(dest);
} else {
if (!IsHex(output)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid scriptPubKey");
@@ -719,38 +783,38 @@ UniValue processImport(const UniValue& data) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid P2SH address / script");
}
- pwalletMain->MarkDirty();
+ pwallet->MarkDirty();
- if (!pwalletMain->HaveWatchOnly(redeemScript) && !pwalletMain->AddWatchOnly(redeemScript)) {
+ if (!pwallet->AddWatchOnly(redeemScript, timestamp)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
}
- if (!pwalletMain->HaveCScript(redeemScript) && !pwalletMain->AddCScript(redeemScript)) {
+ if (!pwallet->HaveCScript(redeemScript) && !pwallet->AddCScript(redeemScript)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet");
}
- CBitcoinAddress redeemAddress = CBitcoinAddress(CScriptID(redeemScript));
- CScript redeemDestination = GetScriptForDestination(redeemAddress.Get());
+ CTxDestination redeem_dest = CScriptID(redeemScript);
+ CScript redeemDestination = GetScriptForDestination(redeem_dest);
- if (::IsMine(*pwalletMain, redeemDestination) == ISMINE_SPENDABLE) {
+ if (::IsMine(*pwallet, redeemDestination) == ISMINE_SPENDABLE) {
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
}
- pwalletMain->MarkDirty();
+ pwallet->MarkDirty();
- if (!pwalletMain->HaveWatchOnly(redeemDestination) && !pwalletMain->AddWatchOnly(redeemDestination)) {
+ if (!pwallet->AddWatchOnly(redeemDestination, timestamp)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
}
// add to address book or update label
- if (address.IsValid()) {
- pwalletMain->SetAddressBook(address.Get(), label, "receive");
+ if (IsValidDestination(dest)) {
+ pwallet->SetAddressBook(dest, label, "receive");
}
// Import private keys.
if (keys.size()) {
for (size_t i = 0; i < keys.size(); i++) {
- const string& privkey = keys[i].get_str();
+ const std::string& privkey = keys[i].get_str();
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(privkey);
@@ -769,22 +833,20 @@ UniValue processImport(const UniValue& data) {
assert(key.VerifyPubKey(pubkey));
CKeyID vchAddress = pubkey.GetID();
- pwalletMain->MarkDirty();
- pwalletMain->SetAddressBook(vchAddress, label, "receive");
+ pwallet->MarkDirty();
+ pwallet->SetAddressBook(vchAddress, label, "receive");
- if (pwalletMain->HaveKey(vchAddress)) {
+ if (pwallet->HaveKey(vchAddress)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Already have this key");
}
- pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = timestamp;
+ pwallet->mapKeyMetadata[vchAddress].nCreateTime = timestamp;
- if (!pwalletMain->AddKeyPubKey(key, pubkey)) {
+ if (!pwallet->AddKeyPubKey(key, pubkey)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
}
- if (timestamp < pwalletMain->nTimeFirstKey) {
- pwalletMain->nTimeFirstKey = timestamp;
- }
+ pwallet->UpdateTimeFirstKey(timestamp);
}
}
@@ -792,7 +854,7 @@ UniValue processImport(const UniValue& data) {
} else {
// Import public keys.
if (pubKeys.size() && keys.size() == 0) {
- const string& strPubKey = pubKeys[0].get_str();
+ const std::string& strPubKey = pubKeys[0].get_str();
if (!IsHex(strPubKey)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey must be a hex string");
@@ -805,53 +867,51 @@ UniValue processImport(const UniValue& data) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey is not a valid public key");
}
- CBitcoinAddress pubKeyAddress = CBitcoinAddress(pubKey.GetID());
+ CTxDestination pubkey_dest = pubKey.GetID();
// Consistency check.
- if (!isScript && !(pubKeyAddress.Get() == address.Get())) {
+ if (!isScript && !(pubkey_dest == dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
}
// Consistency check.
if (isScript) {
- CBitcoinAddress scriptAddress;
CTxDestination destination;
if (ExtractDestination(script, destination)) {
- scriptAddress = CBitcoinAddress(destination);
- if (!(scriptAddress.Get() == pubKeyAddress.Get())) {
+ if (!(destination == pubkey_dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
}
}
}
- CScript pubKeyScript = GetScriptForDestination(pubKeyAddress.Get());
+ CScript pubKeyScript = GetScriptForDestination(pubkey_dest);
- if (::IsMine(*pwalletMain, pubKeyScript) == ISMINE_SPENDABLE) {
+ if (::IsMine(*pwallet, pubKeyScript) == ISMINE_SPENDABLE) {
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
}
- pwalletMain->MarkDirty();
+ pwallet->MarkDirty();
- if (!pwalletMain->HaveWatchOnly(pubKeyScript) && !pwalletMain->AddWatchOnly(pubKeyScript)) {
+ if (!pwallet->AddWatchOnly(pubKeyScript, timestamp)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
}
// add to address book or update label
- if (pubKeyAddress.IsValid()) {
- pwalletMain->SetAddressBook(pubKeyAddress.Get(), label, "receive");
+ if (IsValidDestination(pubkey_dest)) {
+ pwallet->SetAddressBook(pubkey_dest, label, "receive");
}
// TODO Is this necessary?
CScript scriptRawPubKey = GetScriptForRawPubKey(pubKey);
- if (::IsMine(*pwalletMain, scriptRawPubKey) == ISMINE_SPENDABLE) {
+ if (::IsMine(*pwallet, scriptRawPubKey) == ISMINE_SPENDABLE) {
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
}
- pwalletMain->MarkDirty();
+ pwallet->MarkDirty();
- if (!pwalletMain->HaveWatchOnly(scriptRawPubKey) && !pwalletMain->AddWatchOnly(scriptRawPubKey)) {
+ if (!pwallet->AddWatchOnly(scriptRawPubKey, timestamp)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
}
@@ -860,7 +920,7 @@ UniValue processImport(const UniValue& data) {
// Import private keys.
if (keys.size()) {
- const string& strPrivkey = keys[0].get_str();
+ const std::string& strPrivkey = keys[0].get_str();
// Checks.
CBitcoinSecret vchSecret;
@@ -878,63 +938,59 @@ UniValue processImport(const UniValue& data) {
CPubKey pubKey = key.GetPubKey();
assert(key.VerifyPubKey(pubKey));
- CBitcoinAddress pubKeyAddress = CBitcoinAddress(pubKey.GetID());
+ CTxDestination pubkey_dest = pubKey.GetID();
// Consistency check.
- if (!isScript && !(pubKeyAddress.Get() == address.Get())) {
+ if (!isScript && !(pubkey_dest == dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
}
// Consistency check.
if (isScript) {
- CBitcoinAddress scriptAddress;
CTxDestination destination;
if (ExtractDestination(script, destination)) {
- scriptAddress = CBitcoinAddress(destination);
- if (!(scriptAddress.Get() == pubKeyAddress.Get())) {
+ if (!(destination == pubkey_dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
}
}
}
CKeyID vchAddress = pubKey.GetID();
- pwalletMain->MarkDirty();
- pwalletMain->SetAddressBook(vchAddress, label, "receive");
+ pwallet->MarkDirty();
+ pwallet->SetAddressBook(vchAddress, label, "receive");
- if (pwalletMain->HaveKey(vchAddress)) {
+ if (pwallet->HaveKey(vchAddress)) {
return false;
}
- pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = timestamp;
+ pwallet->mapKeyMetadata[vchAddress].nCreateTime = timestamp;
- if (!pwalletMain->AddKeyPubKey(key, pubKey)) {
+ if (!pwallet->AddKeyPubKey(key, pubKey)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
}
- if (timestamp < pwalletMain->nTimeFirstKey) {
- pwalletMain->nTimeFirstKey = timestamp;
- }
+ pwallet->UpdateTimeFirstKey(timestamp);
success = true;
}
// Import scriptPubKey only.
if (pubKeys.size() == 0 && keys.size() == 0) {
- if (::IsMine(*pwalletMain, script) == ISMINE_SPENDABLE) {
+ if (::IsMine(*pwallet, script) == ISMINE_SPENDABLE) {
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
}
- pwalletMain->MarkDirty();
+ pwallet->MarkDirty();
- if (!pwalletMain->HaveWatchOnly(script) && !pwalletMain->AddWatchOnly(script)) {
+ if (!pwallet->AddWatchOnly(script, timestamp)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
}
if (scriptPubKey.getType() == UniValue::VOBJ) {
// add to address book or update label
- if (address.IsValid()) {
- pwalletMain->SetAddressBook(address.Get(), label, "receive");
+ if (IsValidDestination(dest)) {
+ pwallet->SetAddressBook(dest, label, "receive");
}
}
@@ -958,25 +1014,49 @@ UniValue processImport(const UniValue& data) {
}
}
+int64_t GetImportTimestamp(const UniValue& data, int64_t now)
+{
+ if (data.exists("timestamp")) {
+ const UniValue& timestamp = data["timestamp"];
+ if (timestamp.isNum()) {
+ return timestamp.get_int64();
+ } else if (timestamp.isStr() && timestamp.get_str() == "now") {
+ return now;
+ }
+ throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Expected number or \"now\" timestamp value for key. got type %s", uvTypeName(timestamp.type())));
+ }
+ throw JSONRPCError(RPC_TYPE_ERROR, "Missing required timestamp field for key");
+}
+
UniValue importmulti(const JSONRPCRequest& mainRequest)
{
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(mainRequest);
+ if (!EnsureWalletIsAvailable(pwallet, mainRequest.fHelp)) {
+ return NullUniValue;
+ }
+
// clang-format off
if (mainRequest.fHelp || mainRequest.params.size() < 1 || mainRequest.params.size() > 2)
- throw runtime_error(
- "importmulti \"requests\" \"options\"\n\n"
+ throw std::runtime_error(
+ "importmulti \"requests\" ( \"options\" )\n\n"
"Import addresses/scripts (with private or public keys, redeem script (P2SH)), rescanning all addresses in one-shot-only (rescan can be disabled via options).\n\n"
"Arguments:\n"
"1. requests (array, required) Data to be imported\n"
" [ (array of json objects)\n"
" {\n"
" \"scriptPubKey\": \"<script>\" | { \"address\":\"<address>\" }, (string / json, required) Type of scriptPubKey (string for script, json for address)\n"
+ " \"timestamp\": timestamp | \"now\" , (integer / string, required) Creation time of the key in seconds since epoch (Jan 1 1970 GMT),\n"
+ " or the string \"now\" to substitute the current synced blockchain time. The timestamp of the oldest\n"
+ " key will determine how far back blockchain rescans need to begin for missing wallet transactions.\n"
+ " \"now\" can be specified to bypass scanning, for keys which are known to never have been used, and\n"
+ " 0 can be specified to scan the entire blockchain. Blocks up to 2 hours before the earliest key\n"
+ " creation time of all keys being imported by the importmulti call will be scanned.\n"
" \"redeemscript\": \"<script>\" , (string, optional) Allowed only if the scriptPubKey is a P2SH address or a P2SH scriptPubKey\n"
" \"pubkeys\": [\"<pubKey>\", ... ] , (array, optional) Array of strings giving pubkeys that must occur in the output or redeemscript\n"
" \"keys\": [\"<key>\", ... ] , (array, optional) Array of strings giving private keys whose corresponding public keys must occur in the output or redeemscript\n"
- " \"internal\": <true> , (boolean, optional, default: false) Stating whether matching outputs should be be treated as not incoming payments\n"
+ " \"internal\": <true> , (boolean, optional, default: false) Stating whether matching outputs should be treated as not incoming payments\n"
" \"watchonly\": <true> , (boolean, optional, default: false) Stating whether matching outputs should be considered watched even when they're not spendable, only allowed if keys are empty\n"
" \"label\": <label> , (string, optional, default: '') Label to assign to the address (aka account name, for now), only allowed with internal=false\n"
- " \"timestamp\": 1454686740, (integer, optional, default now) Timestamp\n"
" }\n"
" ,...\n"
" ]\n"
@@ -993,18 +1073,15 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
" [{ \"success\": true } , { \"success\": false, \"error\": { \"code\": -1, \"message\": \"Internal Server Error\"} }, ... ]\n");
// clang-format on
- if (!EnsureWalletIsAvailable(mainRequest.fHelp)) {
- return NullUniValue;
- }
- RPCTypeCheck(mainRequest.params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ));
+ RPCTypeCheck(mainRequest.params, {UniValue::VARR, UniValue::VOBJ});
const UniValue& requests = mainRequest.params[0];
//Default options
bool fRescan = true;
- if (mainRequest.params.size() > 1) {
+ if (!mainRequest.params[1].isNull()) {
const UniValue& options = mainRequest.params[1];
if (options.exists("rescan")) {
@@ -1012,8 +1089,14 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
}
}
- LOCK2(cs_main, pwalletMain->cs_wallet);
- EnsureWalletIsUnlocked();
+ LOCK2(cs_main, pwallet->cs_wallet);
+ EnsureWalletIsUnlocked(pwallet);
+
+ // Verify all timestamps are present before importing any keys.
+ const int64_t now = chainActive.Tip() ? chainActive.Tip()->GetMedianTimePast() : 0;
+ for (const UniValue& data : requests.getValues()) {
+ GetImportTimestamp(data, now);
+ }
bool fRunScan = false;
const int64_t minimumTimestamp = 1;
@@ -1027,8 +1110,9 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
UniValue response(UniValue::VARR);
- BOOST_FOREACH (const UniValue& data, requests.getValues()) {
- const UniValue result = processImport(data);
+ for (const UniValue& data : requests.getValues()) {
+ const int64_t timestamp = std::max(GetImportTimestamp(data, now), minimumTimestamp);
+ const UniValue result = ProcessImport(pwallet, data, timestamp);
response.push_back(result);
if (!fRescan) {
@@ -1041,19 +1125,46 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
}
// Get the lowest timestamp.
- const int64_t& timestamp = data.exists("timestamp") && data["timestamp"].get_int64() > minimumTimestamp ? data["timestamp"].get_int64() : minimumTimestamp;
-
if (timestamp < nLowestTimestamp) {
nLowestTimestamp = timestamp;
}
}
- if (fRescan && fRunScan && requests.size() && nLowestTimestamp <= chainActive.Tip()->GetBlockTimeMax()) {
- CBlockIndex* pindex = nLowestTimestamp > minimumTimestamp ? chainActive.FindEarliestAtLeast(nLowestTimestamp) : chainActive.Genesis();
-
- if (pindex) {
- pwalletMain->ScanForWalletTransactions(pindex, true);
- pwalletMain->ReacceptWalletTransactions();
+ if (fRescan && fRunScan && requests.size()) {
+ int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, true /* update */);
+ pwallet->ReacceptWalletTransactions();
+
+ if (scannedTime > nLowestTimestamp) {
+ std::vector<UniValue> results = response.getValues();
+ response.clear();
+ response.setArray();
+ size_t i = 0;
+ for (const UniValue& request : requests.getValues()) {
+ // If key creation date is within the successfully scanned
+ // range, or if the import result already has an error set, let
+ // the result stand unmodified. Otherwise replace the result
+ // with an error message.
+ if (scannedTime <= GetImportTimestamp(request, now) || results.at(i).exists("error")) {
+ response.push_back(results.at(i));
+ } else {
+ UniValue result = UniValue(UniValue::VOBJ);
+ result.pushKV("success", UniValue(false));
+ result.pushKV(
+ "error",
+ JSONRPCError(
+ RPC_MISC_ERROR,
+ strprintf("Rescan failed for key with creation timestamp %d. There was an error reading a "
+ "block from time %d, which is after or within %d seconds of key creation, and "
+ "could contain transactions pertaining to the key. As a result, transactions "
+ "and coins using this key may not appear in the wallet. This error could be "
+ "caused by pruning or data corruption (see bitcoind log for details) and could "
+ "be dealt with by downloading and rescanning the relevant blocks (see -reindex "
+ "and -rescan options).",
+ GetImportTimestamp(request, now), scannedTime - TIMESTAMP_WINDOW - 1, TIMESTAMP_WINDOW)));
+ response.push_back(std::move(result));
+ }
+ ++i;
+ }
}
}
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 2428ef04e2..5d98498a4b 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -8,51 +8,77 @@
#include "chain.h"
#include "consensus/validation.h"
#include "core_io.h"
-#include "init.h"
+#include "httpserver.h"
#include "validation.h"
#include "net.h"
+#include "policy/feerate.h"
+#include "policy/fees.h"
+#include "policy/policy.h"
#include "policy/rbf.h"
+#include "rpc/mining.h"
+#include "rpc/safemode.h"
#include "rpc/server.h"
+#include "script/sign.h"
#include "timedata.h"
#include "util.h"
#include "utilmoneystr.h"
-#include "wallet.h"
-#include "walletdb.h"
+#include "wallet/coincontrol.h"
+#include "wallet/feebumper.h"
+#include "wallet/wallet.h"
+#include "wallet/walletdb.h"
-#include <stdint.h>
+#include <init.h> // For StartShutdown
-#include <boost/assign/list_of.hpp>
+#include <stdint.h>
#include <univalue.h>
-using namespace std;
+static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
-int64_t nWalletUnlockTime;
-static CCriticalSection cs_nWalletUnlockTime;
+CWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
+{
+ if (request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) {
+ // wallet endpoint was used
+ std::string requestedWallet = urlDecode(request.URI.substr(WALLET_ENDPOINT_BASE.size()));
+ for (CWalletRef pwallet : ::vpwallets) {
+ if (pwallet->GetName() == requestedWallet) {
+ return pwallet;
+ }
+ }
+ throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
+ }
+ return ::vpwallets.size() == 1 || (request.fHelp && ::vpwallets.size() > 0) ? ::vpwallets[0] : nullptr;
+}
-std::string HelpRequiringPassphrase()
+std::string HelpRequiringPassphrase(CWallet * const pwallet)
{
- return pwalletMain && pwalletMain->IsCrypted()
+ return pwallet && pwallet->IsCrypted()
? "\nRequires wallet passphrase to be set with walletpassphrase call."
: "";
}
-bool EnsureWalletIsAvailable(bool avoidException)
+bool EnsureWalletIsAvailable(CWallet * const pwallet, bool avoidException)
{
- if (!pwalletMain)
- {
- if (!avoidException)
- throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
- else
- return false;
+ if (pwallet) return true;
+ if (avoidException) return false;
+ if (::vpwallets.empty()) {
+ // Note: It isn't currently possible to trigger this error because
+ // wallet RPC methods aren't registered unless a wallet is loaded. But
+ // this error is being kept as a precaution, because it's possible in
+ // the future that wallet RPC methods might get or remain registered
+ // when no wallets are loaded.
+ throw JSONRPCError(
+ RPC_METHOD_NOT_FOUND, "Method not found (wallet method is disabled because no wallet is loaded)");
}
- return true;
+ throw JSONRPCError(RPC_WALLET_NOT_SPECIFIED,
+ "Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path).");
}
-void EnsureWalletIsUnlocked()
+void EnsureWalletIsUnlocked(CWallet * const pwallet)
{
- if (pwalletMain->IsLocked())
+ if (pwallet->IsLocked()) {
throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
+ }
}
void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
@@ -72,7 +98,7 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
uint256 hash = wtx.GetHash();
entry.push_back(Pair("txid", hash.GetHex()));
UniValue conflicts(UniValue::VARR);
- BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts())
+ for (const uint256& conflict : wtx.GetConflicts())
conflicts.push_back(conflict.GetHex());
entry.push_back(Pair("walletconflicts", conflicts));
entry.push_back(Pair("time", wtx.GetTxTime()));
@@ -90,13 +116,13 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
}
entry.push_back(Pair("bip125-replaceable", rbfStatus));
- BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
+ for (const std::pair<std::string, std::string>& item : wtx.mapValue)
entry.push_back(Pair(item.first, item.second));
}
-string AccountFromValue(const UniValue& value)
+std::string AccountFromValue(const UniValue& value)
{
- string strAccount = value.get_str();
+ std::string strAccount = value.get_str();
if (strAccount == "*")
throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Invalid account name");
return strAccount;
@@ -104,11 +130,13 @@ string AccountFromValue(const UniValue& value)
UniValue getnewaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() > 1)
- throw runtime_error(
+ throw std::runtime_error(
"getnewaddress ( \"account\" )\n"
"\nReturns a new Bitcoin address for receiving payments.\n"
"If 'account' is specified (DEPRECATED), it is added to the address book \n"
@@ -122,45 +150,49 @@ UniValue getnewaddress(const JSONRPCRequest& request)
+ HelpExampleRpc("getnewaddress", "")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
// Parse the account first so we don't generate a key if there's an error
- string strAccount;
- if (request.params.size() > 0)
+ std::string strAccount;
+ if (!request.params[0].isNull())
strAccount = AccountFromValue(request.params[0]);
- if (!pwalletMain->IsLocked())
- pwalletMain->TopUpKeyPool();
+ if (!pwallet->IsLocked()) {
+ pwallet->TopUpKeyPool();
+ }
// Generate a new key that is added to wallet
CPubKey newKey;
- if (!pwalletMain->GetKeyFromPool(newKey))
+ if (!pwallet->GetKeyFromPool(newKey)) {
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
+ }
CKeyID keyID = newKey.GetID();
- pwalletMain->SetAddressBook(keyID, strAccount, "receive");
+ pwallet->SetAddressBook(keyID, strAccount, "receive");
- return CBitcoinAddress(keyID).ToString();
+ return EncodeDestination(keyID);
}
-CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
+CTxDestination GetAccountAddress(CWallet* const pwallet, std::string strAccount, bool bForceNew=false)
{
CPubKey pubKey;
- if (!pwalletMain->GetAccountPubkey(pubKey, strAccount, bForceNew)) {
+ if (!pwallet->GetAccountPubkey(pubKey, strAccount, bForceNew)) {
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
}
- return CBitcoinAddress(pubKey.GetID());
+ return pubKey.GetID();
}
UniValue getaccountaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"getaccountaddress \"account\"\n"
"\nDEPRECATED. Returns the current Bitcoin address for receiving payments to this account.\n"
"\nArguments:\n"
@@ -174,25 +206,27 @@ UniValue getaccountaddress(const JSONRPCRequest& request)
+ HelpExampleRpc("getaccountaddress", "\"myaccount\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
// Parse the account first so we don't generate a key if there's an error
- string strAccount = AccountFromValue(request.params[0]);
+ std::string strAccount = AccountFromValue(request.params[0]);
UniValue ret(UniValue::VSTR);
- ret = GetAccountAddress(strAccount).ToString();
+ ret = EncodeDestination(GetAccountAddress(pwallet, strAccount));
return ret;
}
UniValue getrawchangeaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (request.fHelp || request.params.size() > 1)
- throw runtime_error(
+ if (request.fHelp || request.params.size() > 0)
+ throw std::runtime_error(
"getrawchangeaddress\n"
"\nReturns a new Bitcoin address, for receiving change.\n"
"This is for use with raw transactions, NOT normal use.\n"
@@ -203,62 +237,65 @@ UniValue getrawchangeaddress(const JSONRPCRequest& request)
+ HelpExampleRpc("getrawchangeaddress", "")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- if (!pwalletMain->IsLocked())
- pwalletMain->TopUpKeyPool();
+ if (!pwallet->IsLocked()) {
+ pwallet->TopUpKeyPool();
+ }
- CReserveKey reservekey(pwalletMain);
+ CReserveKey reservekey(pwallet);
CPubKey vchPubKey;
- if (!reservekey.GetReservedKey(vchPubKey))
+ if (!reservekey.GetReservedKey(vchPubKey, true))
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
reservekey.KeepKey();
CKeyID keyID = vchPubKey.GetID();
- return CBitcoinAddress(keyID).ToString();
+ return EncodeDestination(keyID);
}
UniValue setaccount(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"setaccount \"address\" \"account\"\n"
"\nDEPRECATED. Sets the account associated with the given address.\n"
"\nArguments:\n"
"1. \"address\" (string, required) The bitcoin address to be associated with an account.\n"
"2. \"account\" (string, required) The account to assign the address to.\n"
"\nExamples:\n"
- + HelpExampleCli("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"tabby\"")
- + HelpExampleRpc("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"tabby\"")
+ + HelpExampleCli("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"tabby\"")
+ + HelpExampleRpc("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"tabby\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- CBitcoinAddress address(request.params[0].get_str());
- if (!address.IsValid())
+ CTxDestination dest = DecodeDestination(request.params[0].get_str());
+ if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
+ }
- string strAccount;
- if (request.params.size() > 1)
+ std::string strAccount;
+ if (!request.params[1].isNull())
strAccount = AccountFromValue(request.params[1]);
// Only add the account if the address is yours.
- if (IsMine(*pwalletMain, address.Get()))
- {
+ if (IsMine(*pwallet, dest)) {
// Detect when changing the account of an address that is the 'unused current key' of another account:
- if (pwalletMain->mapAddressBook.count(address.Get()))
- {
- string strOldAccount = pwalletMain->mapAddressBook[address.Get()].name;
- if (address == GetAccountAddress(strOldAccount))
- GetAccountAddress(strOldAccount, true);
+ if (pwallet->mapAddressBook.count(dest)) {
+ std::string strOldAccount = pwallet->mapAddressBook[dest].name;
+ if (dest == GetAccountAddress(pwallet, strOldAccount)) {
+ GetAccountAddress(pwallet, strOldAccount, true);
+ }
}
- pwalletMain->SetAddressBook(address.Get(), strAccount, "receive");
+ pwallet->SetAddressBook(dest, strAccount, "receive");
}
else
throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
@@ -269,11 +306,13 @@ UniValue setaccount(const JSONRPCRequest& request)
UniValue getaccount(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"getaccount \"address\"\n"
"\nDEPRECATED. Returns the account associated with the given address.\n"
"\nArguments:\n"
@@ -281,31 +320,35 @@ UniValue getaccount(const JSONRPCRequest& request)
"\nResult:\n"
"\"accountname\" (string) the account address\n"
"\nExamples:\n"
- + HelpExampleCli("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"")
- + HelpExampleRpc("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"")
+ + HelpExampleCli("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\"")
+ + HelpExampleRpc("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- CBitcoinAddress address(request.params[0].get_str());
- if (!address.IsValid())
+ CTxDestination dest = DecodeDestination(request.params[0].get_str());
+ if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
+ }
- string strAccount;
- map<CTxDestination, CAddressBookData>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
- if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.name.empty())
+ std::string strAccount;
+ std::map<CTxDestination, CAddressBookData>::iterator mi = pwallet->mapAddressBook.find(dest);
+ if (mi != pwallet->mapAddressBook.end() && !(*mi).second.name.empty()) {
strAccount = (*mi).second.name;
+ }
return strAccount;
}
UniValue getaddressesbyaccount(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"getaddressesbyaccount \"account\"\n"
"\nDEPRECATED. Returns the list of addresses for the given account.\n"
"\nArguments:\n"
@@ -320,25 +363,25 @@ UniValue getaddressesbyaccount(const JSONRPCRequest& request)
+ HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- string strAccount = AccountFromValue(request.params[0]);
+ std::string strAccount = AccountFromValue(request.params[0]);
// Find all addresses that have the given account
UniValue ret(UniValue::VARR);
- BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
- {
- const CBitcoinAddress& address = item.first;
- const string& strName = item.second.name;
- if (strName == strAccount)
- ret.push_back(address.ToString());
+ for (const std::pair<CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) {
+ const CTxDestination& dest = item.first;
+ const std::string& strName = item.second.name;
+ if (strName == strAccount) {
+ ret.push_back(EncodeDestination(dest));
+ }
}
return ret;
}
-static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew)
+static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew, const CCoinControl& coin_control)
{
- CAmount curBalance = pwalletMain->GetBalance();
+ CAmount curBalance = pwallet->GetBalance();
// Check amount
if (nValue <= 0)
@@ -347,27 +390,28 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr
if (nValue > curBalance)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
- if (pwalletMain->GetBroadcastTransactions() && !g_connman)
+ if (pwallet->GetBroadcastTransactions() && !g_connman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+ }
// Parse Bitcoin address
CScript scriptPubKey = GetScriptForDestination(address);
// Create and send the transaction
- CReserveKey reservekey(pwalletMain);
+ CReserveKey reservekey(pwallet);
CAmount nFeeRequired;
std::string strError;
- vector<CRecipient> vecSend;
+ std::vector<CRecipient> vecSend;
int nChangePosRet = -1;
CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
vecSend.push_back(recipient);
- if (!pwalletMain->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError)) {
+ if (!pwallet->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError, coin_control)) {
if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance)
strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired));
throw JSONRPCError(RPC_WALLET_ERROR, strError);
}
CValidationState state;
- if (!pwalletMain->CommitTransaction(wtxNew, reservekey, g_connman.get(), state)) {
+ if (!pwallet->CommitTransaction(wtxNew, reservekey, g_connman.get(), state)) {
strError = strprintf("Error: The transaction was rejected! Reason given: %s", state.GetRejectReason());
throw JSONRPCError(RPC_WALLET_ERROR, strError);
}
@@ -375,14 +419,16 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr
UniValue sendtoaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (request.fHelp || request.params.size() < 2 || request.params.size() > 5)
- throw runtime_error(
- "sendtoaddress \"address\" amount ( \"comment\" \"comment_to\" subtractfeefromamount )\n"
+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 8)
+ throw std::runtime_error(
+ "sendtoaddress \"address\" amount ( \"comment\" \"comment_to\" subtractfeefromamount replaceable conf_target \"estimate_mode\")\n"
"\nSend an amount to a given address.\n"
- + HelpRequiringPassphrase() +
+ + HelpRequiringPassphrase(pwallet) +
"\nArguments:\n"
"1. \"address\" (string, required) The bitcoin address to send to.\n"
"2. \"amount\" (numeric or string, required) The amount in " + CURRENCY_UNIT + " to send. eg 0.1\n"
@@ -393,6 +439,12 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
" transaction, just kept in your wallet.\n"
"5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n"
" The recipient will receive less bitcoins than you enter in the amount field.\n"
+ "6. replaceable (boolean, optional) Allow this transaction to be replaced by a transaction with higher fees via BIP 125\n"
+ "7. conf_target (numeric, optional) Confirmation target (in blocks)\n"
+ "8. \"estimate_mode\" (string, optional, default=UNSET) The fee estimate mode, must be one of:\n"
+ " \"UNSET\"\n"
+ " \"ECONOMICAL\"\n"
+ " \"CONSERVATIVE\"\n"
"\nResult:\n"
"\"txid\" (string) The transaction id.\n"
"\nExamples:\n"
@@ -402,11 +454,13 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
+ HelpExampleRpc("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ ObserveSafeMode();
+ LOCK2(cs_main, pwallet->cs_wallet);
- CBitcoinAddress address(request.params[0].get_str());
- if (!address.IsValid())
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
+ CTxDestination dest = DecodeDestination(request.params[0].get_str());
+ if (!IsValidDestination(dest)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
+ }
// Amount
CAmount nAmount = AmountFromValue(request.params[1]);
@@ -415,29 +469,48 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
// Wallet comments
CWalletTx wtx;
- if (request.params.size() > 2 && !request.params[2].isNull() && !request.params[2].get_str().empty())
+ if (!request.params[2].isNull() && !request.params[2].get_str().empty())
wtx.mapValue["comment"] = request.params[2].get_str();
- if (request.params.size() > 3 && !request.params[3].isNull() && !request.params[3].get_str().empty())
+ if (!request.params[3].isNull() && !request.params[3].get_str().empty())
wtx.mapValue["to"] = request.params[3].get_str();
bool fSubtractFeeFromAmount = false;
- if (request.params.size() > 4)
+ if (!request.params[4].isNull()) {
fSubtractFeeFromAmount = request.params[4].get_bool();
+ }
- EnsureWalletIsUnlocked();
+ CCoinControl coin_control;
+ if (!request.params[5].isNull()) {
+ coin_control.signalRbf = request.params[5].get_bool();
+ }
- SendMoney(address.Get(), nAmount, fSubtractFeeFromAmount, wtx);
+ if (!request.params[6].isNull()) {
+ coin_control.m_confirm_target = ParseConfirmTarget(request.params[6]);
+ }
+
+ if (!request.params[7].isNull()) {
+ if (!FeeModeFromString(request.params[7].get_str(), coin_control.m_fee_mode)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
+ }
+ }
+
+
+ EnsureWalletIsUnlocked(pwallet);
+
+ SendMoney(pwallet, dest, nAmount, fSubtractFeeFromAmount, wtx, coin_control);
return wtx.GetHash().GetHex();
}
UniValue listaddressgroupings(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (request.fHelp)
- throw runtime_error(
+ if (request.fHelp || request.params.size() != 0)
+ throw std::runtime_error(
"listaddressgroupings\n"
"\nLists groups of addresses which have had their common ownership\n"
"made public by common use as inputs or as the resulting change\n"
@@ -459,21 +532,22 @@ UniValue listaddressgroupings(const JSONRPCRequest& request)
+ HelpExampleRpc("listaddressgroupings", "")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ ObserveSafeMode();
+ LOCK2(cs_main, pwallet->cs_wallet);
UniValue jsonGroupings(UniValue::VARR);
- map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances();
- BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
- {
+ std::map<CTxDestination, CAmount> balances = pwallet->GetAddressBalances();
+ for (const std::set<CTxDestination>& grouping : pwallet->GetAddressGroupings()) {
UniValue jsonGrouping(UniValue::VARR);
- BOOST_FOREACH(CTxDestination address, grouping)
+ for (const CTxDestination& address : grouping)
{
UniValue addressInfo(UniValue::VARR);
- addressInfo.push_back(CBitcoinAddress(address).ToString());
+ addressInfo.push_back(EncodeDestination(address));
addressInfo.push_back(ValueFromAmount(balances[address]));
{
- if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
- addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name);
+ if (pwallet->mapAddressBook.find(address) != pwallet->mapAddressBook.end()) {
+ addressInfo.push_back(pwallet->mapAddressBook.find(address)->second.name);
+ }
}
jsonGrouping.push_back(addressInfo);
}
@@ -484,14 +558,16 @@ UniValue listaddressgroupings(const JSONRPCRequest& request)
UniValue signmessage(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() != 2)
- throw runtime_error(
+ throw std::runtime_error(
"signmessage \"address\" \"message\"\n"
"\nSign a message with the private key of an address"
- + HelpRequiringPassphrase() + "\n"
+ + HelpRequiringPassphrase(pwallet) + "\n"
"\nArguments:\n"
"1. \"address\" (string, required) The bitcoin address to use for the private key.\n"
"2. \"message\" (string, required) The message to create a signature of.\n"
@@ -501,50 +577,55 @@ UniValue signmessage(const JSONRPCRequest& request)
"\nUnlock the wallet for 30 seconds\n"
+ HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
"\nCreate the signature\n"
- + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"my message\"") +
+ + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") +
"\nVerify the signature\n"
- + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") +
+ + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
"\nAs json rpc\n"
- + HelpExampleRpc("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"my message\"")
+ + HelpExampleRpc("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"my message\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- EnsureWalletIsUnlocked();
+ EnsureWalletIsUnlocked(pwallet);
- string strAddress = request.params[0].get_str();
- string strMessage = request.params[1].get_str();
+ std::string strAddress = request.params[0].get_str();
+ std::string strMessage = request.params[1].get_str();
- CBitcoinAddress addr(strAddress);
- if (!addr.IsValid())
+ CTxDestination dest = DecodeDestination(strAddress);
+ if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
+ }
- CKeyID keyID;
- if (!addr.GetKeyID(keyID))
+ const CKeyID *keyID = boost::get<CKeyID>(&dest);
+ if (!keyID) {
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
+ }
CKey key;
- if (!pwalletMain->GetKey(keyID, key))
+ if (!pwallet->GetKey(*keyID, key)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
+ }
CHashWriter ss(SER_GETHASH, 0);
ss << strMessageMagic;
ss << strMessage;
- vector<unsigned char> vchSig;
+ std::vector<unsigned char> vchSig;
if (!key.SignCompact(ss.GetHash(), vchSig))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
- return EncodeBase64(&vchSig[0], vchSig.size());
+ return EncodeBase64(vchSig.data(), vchSig.size());
}
UniValue getreceivedbyaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"getreceivedbyaddress \"address\" ( minconf )\n"
"\nReturns the total amount received by the given address in transactions with at least minconf confirmations.\n"
"\nArguments:\n"
@@ -554,39 +635,41 @@ UniValue getreceivedbyaddress(const JSONRPCRequest& request)
"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\"") +
+ + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\"") +
"\nThe amount including unconfirmed transactions, zero confirmations\n"
- + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" 0") +
- "\nThe amount with at least 6 confirmation, very safe\n"
- + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" 6") +
+ + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" 0") +
+ "\nThe amount with at least 6 confirmations\n"
+ + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" 6") +
"\nAs a json rpc call\n"
- + HelpExampleRpc("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", 6")
+ + HelpExampleRpc("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", 6")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ ObserveSafeMode();
+ LOCK2(cs_main, pwallet->cs_wallet);
// Bitcoin address
- CBitcoinAddress address = CBitcoinAddress(request.params[0].get_str());
- if (!address.IsValid())
+ CTxDestination dest = DecodeDestination(request.params[0].get_str());
+ if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
- CScript scriptPubKey = GetScriptForDestination(address.Get());
- if (!IsMine(*pwalletMain, scriptPubKey))
+ }
+ CScript scriptPubKey = GetScriptForDestination(dest);
+ if (!IsMine(*pwallet, scriptPubKey)) {
return ValueFromAmount(0);
+ }
// Minimum confirmations
int nMinDepth = 1;
- if (request.params.size() > 1)
+ if (!request.params[1].isNull())
nMinDepth = request.params[1].get_int();
// Tally
CAmount nAmount = 0;
- for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
- {
- const CWalletTx& wtx = (*it).second;
+ for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
+ const CWalletTx& wtx = pairWtx.second;
if (wtx.IsCoinBase() || !CheckFinalTx(*wtx.tx))
continue;
- BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
+ for (const CTxOut& txout : wtx.tx->vout)
if (txout.scriptPubKey == scriptPubKey)
if (wtx.GetDepthInMainChain() >= nMinDepth)
nAmount += txout.nValue;
@@ -598,11 +681,13 @@ UniValue getreceivedbyaddress(const JSONRPCRequest& request)
UniValue getreceivedbyaccount(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"getreceivedbyaccount \"account\" ( minconf )\n"
"\nDEPRECATED. Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n"
"\nArguments:\n"
@@ -615,37 +700,38 @@ UniValue getreceivedbyaccount(const JSONRPCRequest& request)
+ HelpExampleCli("getreceivedbyaccount", "\"\"") +
"\nAmount received at the tabby account including unconfirmed amounts with zero confirmations\n"
+ HelpExampleCli("getreceivedbyaccount", "\"tabby\" 0") +
- "\nThe amount with at least 6 confirmation, very safe\n"
+ "\nThe amount with at least 6 confirmations\n"
+ HelpExampleCli("getreceivedbyaccount", "\"tabby\" 6") +
"\nAs a json rpc call\n"
+ HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ ObserveSafeMode();
+ LOCK2(cs_main, pwallet->cs_wallet);
// Minimum confirmations
int nMinDepth = 1;
- if (request.params.size() > 1)
+ if (!request.params[1].isNull())
nMinDepth = request.params[1].get_int();
// Get the set of pub keys assigned to account
- string strAccount = AccountFromValue(request.params[0]);
- set<CTxDestination> setAddress = pwalletMain->GetAccountAddresses(strAccount);
+ std::string strAccount = AccountFromValue(request.params[0]);
+ std::set<CTxDestination> setAddress = pwallet->GetAccountAddresses(strAccount);
// Tally
CAmount nAmount = 0;
- for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
- {
- const CWalletTx& wtx = (*it).second;
+ for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
+ const CWalletTx& wtx = pairWtx.second;
if (wtx.IsCoinBase() || !CheckFinalTx(*wtx.tx))
continue;
- BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
+ for (const CTxOut& txout : wtx.tx->vout)
{
CTxDestination address;
- if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
+ if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwallet, address) && setAddress.count(address)) {
if (wtx.GetDepthInMainChain() >= nMinDepth)
nAmount += txout.nValue;
+ }
}
}
@@ -655,102 +741,105 @@ UniValue getreceivedbyaccount(const JSONRPCRequest& request)
UniValue getbalance(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() > 3)
- throw runtime_error(
+ throw std::runtime_error(
"getbalance ( \"account\" minconf include_watchonly )\n"
"\nIf account is not specified, returns the server's total available balance.\n"
"If account is specified (DEPRECATED), returns the balance in the account.\n"
"Note that the account \"\" is not the same as leaving the parameter out.\n"
"The server total may be different to the balance in the default \"\" account.\n"
"\nArguments:\n"
- "1. \"account\" (string, optional) DEPRECATED. The selected account, or \"*\" for entire wallet. It may be the default account using \"\".\n"
- "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
+ "1. \"account\" (string, optional) DEPRECATED. The account string may be given as a\n"
+ " specific account name to find the balance associated with wallet keys in\n"
+ " a named account, or as the empty string (\"\") to find the balance\n"
+ " associated with wallet keys not in any named account, or as \"*\" to find\n"
+ " the balance associated with all wallet keys regardless of account.\n"
+ " When this option is specified, it calculates the balance in a different\n"
+ " way than when it is not specified, and which can count spends twice when\n"
+ " there are conflicting pending transactions (such as those created by\n"
+ " the bumpfee command), temporarily resulting in low or even negative\n"
+ " balances. In general, account balance calculation is not considered\n"
+ " reliable and has resulted in confusing outcomes, so it is recommended to\n"
+ " avoid passing this argument.\n"
+ "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
"3. include_watchonly (bool, optional, default=false) Also include balance in watch-only addresses (see 'importaddress')\n"
"\nResult:\n"
"amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this account.\n"
"\nExamples:\n"
- "\nThe total amount in the wallet\n"
+ "\nThe total amount in the wallet with 1 or more confirmations\n"
+ HelpExampleCli("getbalance", "") +
- "\nThe total amount in the wallet at least 5 blocks confirmed\n"
+ "\nThe total amount in the wallet at least 6 blocks confirmed\n"
+ HelpExampleCli("getbalance", "\"*\" 6") +
"\nAs a json rpc call\n"
+ HelpExampleRpc("getbalance", "\"*\", 6")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ ObserveSafeMode();
+ LOCK2(cs_main, pwallet->cs_wallet);
- if (request.params.size() == 0)
- return ValueFromAmount(pwalletMain->GetBalance());
-
- int nMinDepth = 1;
- if (request.params.size() > 1)
- nMinDepth = request.params[1].get_int();
- isminefilter filter = ISMINE_SPENDABLE;
- if(request.params.size() > 2)
- if(request.params[2].get_bool())
- filter = filter | ISMINE_WATCH_ONLY;
+ const UniValue& account_value = request.params[0];
+ const UniValue& minconf = request.params[1];
+ const UniValue& include_watchonly = request.params[2];
- if (request.params[0].get_str() == "*") {
- // Calculate total balance a different way from GetBalance()
- // (GetBalance() sums up all unspent TxOuts)
- // 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 (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
- continue;
-
- CAmount allFee;
- string strSentAccount;
- list<COutputEntry> listReceived;
- list<COutputEntry> listSent;
- wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
- if (wtx.GetDepthInMainChain() >= nMinDepth)
- {
- BOOST_FOREACH(const COutputEntry& r, listReceived)
- nBalance += r.amount;
- }
- BOOST_FOREACH(const COutputEntry& s, listSent)
- nBalance -= s.amount;
- nBalance -= allFee;
+ if (account_value.isNull()) {
+ if (!minconf.isNull()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER,
+ "getbalance minconf option is only currently supported if an account is specified");
}
- return ValueFromAmount(nBalance);
+ if (!include_watchonly.isNull()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER,
+ "getbalance include_watchonly option is only currently supported if an account is specified");
+ }
+ return ValueFromAmount(pwallet->GetBalance());
}
- string strAccount = AccountFromValue(request.params[0]);
+ const std::string& account_param = account_value.get_str();
+ const std::string* account = account_param != "*" ? &account_param : nullptr;
- CAmount nBalance = pwalletMain->GetAccountBalance(strAccount, nMinDepth, filter);
+ int nMinDepth = 1;
+ if (!minconf.isNull())
+ nMinDepth = minconf.get_int();
+ isminefilter filter = ISMINE_SPENDABLE;
+ if(!include_watchonly.isNull())
+ if(include_watchonly.get_bool())
+ filter = filter | ISMINE_WATCH_ONLY;
- return ValueFromAmount(nBalance);
+ return ValueFromAmount(pwallet->GetLegacyBalance(filter, nMinDepth, account));
}
UniValue getunconfirmedbalance(const JSONRPCRequest &request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() > 0)
- throw runtime_error(
+ throw std::runtime_error(
"getunconfirmedbalance\n"
"Returns the server's total unconfirmed balance\n");
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ ObserveSafeMode();
+ LOCK2(cs_main, pwallet->cs_wallet);
- return ValueFromAmount(pwalletMain->GetUnconfirmedBalance());
+ return ValueFromAmount(pwallet->GetUnconfirmedBalance());
}
UniValue movecmd(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() < 3 || request.params.size() > 5)
- throw runtime_error(
+ throw std::runtime_error(
"move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n"
"\nDEPRECATED. Move a specified amount from one account in your wallet to another.\n"
"\nArguments:\n"
@@ -770,22 +859,24 @@ UniValue movecmd(const JSONRPCRequest& request)
+ HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ ObserveSafeMode();
+ LOCK2(cs_main, pwallet->cs_wallet);
- string strFrom = AccountFromValue(request.params[0]);
- string strTo = AccountFromValue(request.params[1]);
+ std::string strFrom = AccountFromValue(request.params[0]);
+ std::string strTo = AccountFromValue(request.params[1]);
CAmount nAmount = AmountFromValue(request.params[2]);
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
- if (request.params.size() > 3)
+ if (!request.params[3].isNull())
// unused parameter, used to be nMinDepth, keep type-checking it though
(void)request.params[3].get_int();
- string strComment;
- if (request.params.size() > 4)
+ std::string strComment;
+ if (!request.params[4].isNull())
strComment = request.params[4].get_str();
- if (!pwalletMain->AccountMove(strFrom, strTo, nAmount, strComment))
+ if (!pwallet->AccountMove(strFrom, strTo, nAmount, strComment)) {
throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
+ }
return true;
}
@@ -793,16 +884,21 @@ UniValue movecmd(const JSONRPCRequest& request)
UniValue sendfrom(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() < 3 || request.params.size() > 6)
- throw runtime_error(
+ throw std::runtime_error(
"sendfrom \"fromaccount\" \"toaddress\" amount ( minconf \"comment\" \"comment_to\" )\n"
"\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a bitcoin address."
- + HelpRequiringPassphrase() + "\n"
+ + HelpRequiringPassphrase(pwallet) + "\n"
"\nArguments:\n"
"1. \"fromaccount\" (string, required) The name of the account to send funds from. May be the default account using \"\".\n"
+ " Specifying an account does not influence coin selection, but it does associate the newly created\n"
+ " transaction with the account, so the account's balance computation and transaction history can reflect\n"
+ " the spend.\n"
"2. \"toaddress\" (string, required) The bitcoin address to send funds to.\n"
"3. amount (numeric or string, 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"
@@ -822,34 +918,37 @@ UniValue sendfrom(const JSONRPCRequest& request)
+ HelpExampleRpc("sendfrom", "\"tabby\", \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.01, 6, \"donation\", \"seans outpost\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ ObserveSafeMode();
+ LOCK2(cs_main, pwallet->cs_wallet);
- string strAccount = AccountFromValue(request.params[0]);
- CBitcoinAddress address(request.params[1].get_str());
- if (!address.IsValid())
+ std::string strAccount = AccountFromValue(request.params[0]);
+ CTxDestination dest = DecodeDestination(request.params[1].get_str());
+ if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
+ }
CAmount nAmount = AmountFromValue(request.params[2]);
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
int nMinDepth = 1;
- if (request.params.size() > 3)
+ if (!request.params[3].isNull())
nMinDepth = request.params[3].get_int();
CWalletTx wtx;
wtx.strFromAccount = strAccount;
- if (request.params.size() > 4 && !request.params[4].isNull() && !request.params[4].get_str().empty())
+ if (!request.params[4].isNull() && !request.params[4].get_str().empty())
wtx.mapValue["comment"] = request.params[4].get_str();
- if (request.params.size() > 5 && !request.params[5].isNull() && !request.params[5].get_str().empty())
+ if (!request.params[5].isNull() && !request.params[5].get_str().empty())
wtx.mapValue["to"] = request.params[5].get_str();
- EnsureWalletIsUnlocked();
+ EnsureWalletIsUnlocked(pwallet);
// Check funds
- CAmount nBalance = pwalletMain->GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
+ CAmount nBalance = pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, &strAccount);
if (nAmount > nBalance)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
- SendMoney(address.Get(), nAmount, false, wtx);
+ CCoinControl no_coin_control; // This is a deprecated API
+ SendMoney(pwallet, dest, nAmount, false, wtx, no_coin_control);
return wtx.GetHash().GetHex();
}
@@ -857,14 +956,16 @@ UniValue sendfrom(const JSONRPCRequest& request)
UniValue sendmany(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (request.fHelp || request.params.size() < 2 || request.params.size() > 5)
- throw runtime_error(
- "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n"
+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 8)
+ throw std::runtime_error(
+ "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] replaceable conf_target \"estimate_mode\")\n"
"\nSend multiple times. Amounts are double-precision floating point numbers."
- + HelpRequiringPassphrase() + "\n"
+ + HelpRequiringPassphrase(pwallet) + "\n"
"\nArguments:\n"
"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"
@@ -882,56 +983,80 @@ UniValue sendmany(const JSONRPCRequest& request)
" \"address\" (string) Subtract fee from this address\n"
" ,...\n"
" ]\n"
- "\nResult:\n"
+ "6. replaceable (boolean, optional) Allow this transaction to be replaced by a transaction with higher fees via BIP 125\n"
+ "7. conf_target (numeric, optional) Confirmation target (in blocks)\n"
+ "8. \"estimate_mode\" (string, optional, default=UNSET) The fee estimate mode, must be one of:\n"
+ " \"UNSET\"\n"
+ " \"ECONOMICAL\"\n"
+ " \"CONSERVATIVE\"\n"
+ "\nResult:\n"
"\"txid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
" the number of addresses.\n"
"\nExamples:\n"
"\nSend two amounts to two different addresses:\n"
- + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") +
+ + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") +
"\nSend two amounts to two different addresses setting the confirmation and comment:\n"
- + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 6 \"testing\"") +
+ + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 6 \"testing\"") +
"\nSend two amounts to two different addresses, subtract fee from amount:\n"
- + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 1 \"\" \"[\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\",\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\"]\"") +
+ + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 1 \"\" \"[\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\",\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\"]\"") +
"\nAs a json rpc call\n"
- + HelpExampleRpc("sendmany", "\"\", \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"")
+ + HelpExampleRpc("sendmany", "\"\", \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ ObserveSafeMode();
+ LOCK2(cs_main, pwallet->cs_wallet);
- if (pwalletMain->GetBroadcastTransactions() && !g_connman)
+ if (pwallet->GetBroadcastTransactions() && !g_connman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+ }
- string strAccount = AccountFromValue(request.params[0]);
+ std::string strAccount = AccountFromValue(request.params[0]);
UniValue sendTo = request.params[1].get_obj();
int nMinDepth = 1;
- if (request.params.size() > 2)
+ if (!request.params[2].isNull())
nMinDepth = request.params[2].get_int();
CWalletTx wtx;
wtx.strFromAccount = strAccount;
- if (request.params.size() > 3 && !request.params[3].isNull() && !request.params[3].get_str().empty())
+ if (!request.params[3].isNull() && !request.params[3].get_str().empty())
wtx.mapValue["comment"] = request.params[3].get_str();
UniValue subtractFeeFromAmount(UniValue::VARR);
- if (request.params.size() > 4)
+ if (!request.params[4].isNull())
subtractFeeFromAmount = request.params[4].get_array();
- set<CBitcoinAddress> setAddress;
- vector<CRecipient> vecSend;
+ CCoinControl coin_control;
+ if (!request.params[5].isNull()) {
+ coin_control.signalRbf = request.params[5].get_bool();
+ }
+
+ if (!request.params[6].isNull()) {
+ coin_control.m_confirm_target = ParseConfirmTarget(request.params[6]);
+ }
+
+ if (!request.params[7].isNull()) {
+ if (!FeeModeFromString(request.params[7].get_str(), coin_control.m_fee_mode)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
+ }
+ }
+
+ std::set<CTxDestination> destinations;
+ std::vector<CRecipient> vecSend;
CAmount totalAmount = 0;
- vector<string> keys = sendTo.getKeys();
- BOOST_FOREACH(const string& name_, keys)
- {
- CBitcoinAddress address(name_);
- if (!address.IsValid())
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+name_);
+ std::vector<std::string> keys = sendTo.getKeys();
+ for (const std::string& name_ : keys) {
+ CTxDestination dest = DecodeDestination(name_);
+ if (!IsValidDestination(dest)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + name_);
+ }
- if (setAddress.count(address))
- throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_);
- setAddress.insert(address);
+ if (destinations.count(dest)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_);
+ }
+ destinations.insert(dest);
- CScript scriptPubKey = GetScriptForDestination(address.Get());
+ CScript scriptPubKey = GetScriptForDestination(dest);
CAmount nAmount = AmountFromValue(sendTo[name_]);
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
@@ -948,23 +1073,23 @@ UniValue sendmany(const JSONRPCRequest& request)
vecSend.push_back(recipient);
}
- EnsureWalletIsUnlocked();
+ EnsureWalletIsUnlocked(pwallet);
// Check funds
- CAmount nBalance = pwalletMain->GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
+ CAmount nBalance = pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, &strAccount);
if (totalAmount > nBalance)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
// Send
- CReserveKey keyChange(pwalletMain);
+ CReserveKey keyChange(pwallet);
CAmount nFeeRequired = 0;
int nChangePosRet = -1;
- string strFailReason;
- bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason);
+ std::string strFailReason;
+ bool fCreated = pwallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason, coin_control);
if (!fCreated)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
CValidationState state;
- if (!pwalletMain->CommitTransaction(wtx, keyChange, g_connman.get(), state)) {
+ if (!pwallet->CommitTransaction(wtx, keyChange, g_connman.get(), state)) {
strFailReason = strprintf("Transaction commit failed:: %s", state.GetRejectReason());
throw JSONRPCError(RPC_WALLET_ERROR, strFailReason);
}
@@ -973,16 +1098,18 @@ UniValue sendmany(const JSONRPCRequest& request)
}
// Defined in rpc/misc.cpp
-extern CScript _createmultisig_redeemScript(const UniValue& params);
+extern CScript _createmultisig_redeemScript(CWallet * const pwallet, const UniValue& params);
UniValue addmultisigaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
{
- string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
+ std::string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
"\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
"Each key is a Bitcoin address or hex-encoded public key.\n"
"If 'account' is specified (DEPRECATED), assign address to that account.\n"
@@ -1005,118 +1132,162 @@ UniValue addmultisigaddress(const JSONRPCRequest& request)
"\nAs json rpc call\n"
+ HelpExampleRpc("addmultisigaddress", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
;
- throw runtime_error(msg);
+ throw std::runtime_error(msg);
}
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- string strAccount;
- if (request.params.size() > 2)
+ std::string strAccount;
+ if (!request.params[2].isNull())
strAccount = AccountFromValue(request.params[2]);
// Construct using pay-to-script-hash:
- CScript inner = _createmultisig_redeemScript(request.params);
+ CScript inner = _createmultisig_redeemScript(pwallet, request.params);
CScriptID innerID(inner);
- pwalletMain->AddCScript(inner);
+ pwallet->AddCScript(inner);
- pwalletMain->SetAddressBook(innerID, strAccount, "send");
- return CBitcoinAddress(innerID).ToString();
+ pwallet->SetAddressBook(innerID, strAccount, "send");
+ return EncodeDestination(innerID);
}
class Witnessifier : public boost::static_visitor<bool>
{
public:
- CScriptID result;
+ CWallet * const pwallet;
+ CTxDestination result;
+ bool already_witness;
- bool operator()(const CNoDestination &dest) const { return false; }
+ explicit Witnessifier(CWallet *_pwallet) : pwallet(_pwallet), already_witness(false) {}
bool operator()(const CKeyID &keyID) {
- CPubKey pubkey;
- if (pwalletMain) {
+ if (pwallet) {
CScript basescript = GetScriptForDestination(keyID);
- isminetype typ;
- typ = IsMine(*pwalletMain, basescript, SIGVERSION_WITNESS_V0);
- if (typ != ISMINE_SPENDABLE && typ != ISMINE_WATCH_SOLVABLE)
- return false;
CScript witscript = GetScriptForWitness(basescript);
- pwalletMain->AddCScript(witscript);
- result = CScriptID(witscript);
- return true;
+ SignatureData sigs;
+ // This check is to make sure that the script we created can actually be solved for and signed by us
+ // if we were to have the private keys. This is just to make sure that the script is valid and that,
+ // if found in a transaction, we would still accept and relay that transaction.
+ if (!ProduceSignature(DummySignatureCreator(pwallet), witscript, sigs) ||
+ !VerifyScript(sigs.scriptSig, witscript, &sigs.scriptWitness, MANDATORY_SCRIPT_VERIFY_FLAGS | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, DummySignatureCreator(pwallet).Checker())) {
+ return false;
+ }
+ return ExtractDestination(witscript, result);
}
return false;
}
bool operator()(const CScriptID &scriptID) {
CScript subscript;
- if (pwalletMain && pwalletMain->GetCScript(scriptID, subscript)) {
+ if (pwallet && pwallet->GetCScript(scriptID, subscript)) {
int witnessversion;
std::vector<unsigned char> witprog;
if (subscript.IsWitnessProgram(witnessversion, witprog)) {
- result = scriptID;
+ ExtractDestination(subscript, result);
+ already_witness = true;
return true;
}
- isminetype typ;
- typ = IsMine(*pwalletMain, subscript, SIGVERSION_WITNESS_V0);
- if (typ != ISMINE_SPENDABLE && typ != ISMINE_WATCH_SOLVABLE)
- return false;
CScript witscript = GetScriptForWitness(subscript);
- pwalletMain->AddCScript(witscript);
- result = CScriptID(witscript);
- return true;
+ SignatureData sigs;
+ // This check is to make sure that the script we created can actually be solved for and signed by us
+ // if we were to have the private keys. This is just to make sure that the script is valid and that,
+ // if found in a transaction, we would still accept and relay that transaction.
+ if (!ProduceSignature(DummySignatureCreator(pwallet), witscript, sigs) ||
+ !VerifyScript(sigs.scriptSig, witscript, &sigs.scriptWitness, MANDATORY_SCRIPT_VERIFY_FLAGS | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, DummySignatureCreator(pwallet).Checker())) {
+ return false;
+ }
+ return ExtractDestination(witscript, result);
}
return false;
}
+
+ bool operator()(const WitnessV0KeyHash& id)
+ {
+ already_witness = true;
+ result = id;
+ return true;
+ }
+
+ bool operator()(const WitnessV0ScriptHash& id)
+ {
+ already_witness = true;
+ result = id;
+ return true;
+ }
+
+ template<typename T>
+ bool operator()(const T& dest) { return false; }
};
UniValue addwitnessaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 1)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
{
- string msg = "addwitnessaddress \"address\"\n"
+ std::string msg = "addwitnessaddress \"address\" ( p2sh )\n"
"\nAdd a witness address for a script (with pubkey or redeemscript known).\n"
"It returns the witness script.\n"
"\nArguments:\n"
"1. \"address\" (string, required) An address known to the wallet\n"
+ "2. p2sh (bool, optional, default=true) Embed inside P2SH\n"
"\nResult:\n"
- "\"witnessaddress\", (string) The value of the new address (P2SH of witness script).\n"
+ "\"witnessaddress\", (string) The value of the new address (P2SH or BIP173).\n"
"}\n"
;
- throw runtime_error(msg);
+ throw std::runtime_error(msg);
}
{
LOCK(cs_main);
- if (!IsWitnessEnabled(chainActive.Tip(), Params().GetConsensus()) && !GetBoolArg("-walletprematurewitness", false)) {
+ if (!IsWitnessEnabled(chainActive.Tip(), Params().GetConsensus()) && !gArgs.GetBoolArg("-walletprematurewitness", false)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Segregated witness not enabled on network");
}
}
- CBitcoinAddress address(request.params[0].get_str());
- if (!address.IsValid())
+ CTxDestination dest = DecodeDestination(request.params[0].get_str());
+ if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
+ }
+
+ bool p2sh = true;
+ if (!request.params[1].isNull()) {
+ p2sh = request.params[1].get_bool();
+ }
- Witnessifier w;
- CTxDestination dest = address.Get();
+ Witnessifier w(pwallet);
bool ret = boost::apply_visitor(w, dest);
if (!ret) {
throw JSONRPCError(RPC_WALLET_ERROR, "Public key or redeemscript not known to wallet, or the key is uncompressed");
}
- pwalletMain->SetAddressBook(w.result, "", "receive");
+ CScript witprogram = GetScriptForDestination(w.result);
- return CBitcoinAddress(w.result).ToString();
+ if (p2sh) {
+ w.result = CScriptID(witprogram);
+ }
+
+ if (w.already_witness) {
+ if (!(dest == w.result)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Cannot convert between witness address types");
+ }
+ } else {
+ pwallet->AddCScript(witprogram);
+ pwallet->SetAddressBook(w.result, "", "receive");
+ }
+
+ return EncodeDestination(w.result);
}
struct tallyitem
{
CAmount nAmount;
int nConf;
- vector<uint256> txids;
+ std::vector<uint256> txids;
bool fIsWatchonly;
tallyitem()
{
@@ -1126,28 +1297,27 @@ struct tallyitem
}
};
-UniValue ListReceived(const UniValue& params, bool fByAccounts)
+UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByAccounts)
{
// Minimum confirmations
int nMinDepth = 1;
- if (params.size() > 0)
+ if (!params[0].isNull())
nMinDepth = params[0].get_int();
// Whether to include empty accounts
bool fIncludeEmpty = false;
- if (params.size() > 1)
+ if (!params[1].isNull())
fIncludeEmpty = params[1].get_bool();
isminefilter filter = ISMINE_SPENDABLE;
- if(params.size() > 2)
+ if(!params[2].isNull())
if(params[2].get_bool())
filter = filter | ISMINE_WATCH_ONLY;
// Tally
- map<CBitcoinAddress, tallyitem> mapTally;
- for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
- {
- const CWalletTx& wtx = (*it).second;
+ std::map<CTxDestination, tallyitem> mapTally;
+ for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
+ const CWalletTx& wtx = pairWtx.second;
if (wtx.IsCoinBase() || !CheckFinalTx(*wtx.tx))
continue;
@@ -1156,19 +1326,19 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts)
if (nDepth < nMinDepth)
continue;
- BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
+ for (const CTxOut& txout : wtx.tx->vout)
{
CTxDestination address;
if (!ExtractDestination(txout.scriptPubKey, address))
continue;
- isminefilter mine = IsMine(*pwalletMain, address);
+ isminefilter mine = IsMine(*pwallet, address);
if(!(mine & filter))
continue;
tallyitem& item = mapTally[address];
item.nAmount += txout.nValue;
- item.nConf = min(item.nConf, nDepth);
+ item.nConf = std::min(item.nConf, nDepth);
item.txids.push_back(wtx.GetHash());
if (mine & ISMINE_WATCH_ONLY)
item.fIsWatchonly = true;
@@ -1177,12 +1347,11 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts)
// Reply
UniValue ret(UniValue::VARR);
- map<string, tallyitem> mapAccountTally;
- BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
- {
- const CBitcoinAddress& address = item.first;
- const string& strAccount = item.second.name;
- map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
+ std::map<std::string, tallyitem> mapAccountTally;
+ for (const std::pair<CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) {
+ const CTxDestination& dest = item.first;
+ const std::string& strAccount = item.second.name;
+ std::map<CTxDestination, tallyitem>::iterator it = mapTally.find(dest);
if (it == mapTally.end() && !fIncludeEmpty)
continue;
@@ -1200,7 +1369,7 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts)
{
tallyitem& _item = mapAccountTally[strAccount];
_item.nAmount += nAmount;
- _item.nConf = min(_item.nConf, nConf);
+ _item.nConf = std::min(_item.nConf, nConf);
_item.fIsWatchonly = fIsWatchonly;
}
else
@@ -1208,7 +1377,7 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts)
UniValue obj(UniValue::VOBJ);
if(fIsWatchonly)
obj.push_back(Pair("involvesWatchonly", true));
- obj.push_back(Pair("address", address.ToString()));
+ obj.push_back(Pair("address", EncodeDestination(dest)));
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)));
@@ -1217,7 +1386,7 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts)
UniValue transactions(UniValue::VARR);
if (it != mapTally.end())
{
- BOOST_FOREACH(const uint256& _item, (*it).second.txids)
+ for (const uint256& _item : (*it).second.txids)
{
transactions.push_back(_item.GetHex());
}
@@ -1229,7 +1398,7 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts)
if (fByAccounts)
{
- for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
+ for (std::map<std::string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
{
CAmount nAmount = (*it).second.nAmount;
int nConf = (*it).second.nConf;
@@ -1248,11 +1417,13 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts)
UniValue listreceivedbyaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() > 3)
- throw runtime_error(
+ throw std::runtime_error(
"listreceivedbyaddress ( minconf include_empty include_watchonly)\n"
"\nList balances by receiving address.\n"
"\nArguments:\n"
@@ -1283,18 +1454,21 @@ UniValue listreceivedbyaddress(const JSONRPCRequest& request)
+ HelpExampleRpc("listreceivedbyaddress", "6, true, true")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ ObserveSafeMode();
+ LOCK2(cs_main, pwallet->cs_wallet);
- return ListReceived(request.params, false);
+ return ListReceived(pwallet, request.params, false);
}
UniValue listreceivedbyaccount(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() > 3)
- throw runtime_error(
+ throw std::runtime_error(
"listreceivedbyaccount ( minconf include_empty include_watchonly)\n"
"\nDEPRECATED. List balances by account.\n"
"\nArguments:\n"
@@ -1320,44 +1494,58 @@ UniValue listreceivedbyaccount(const JSONRPCRequest& request)
+ HelpExampleRpc("listreceivedbyaccount", "6, true, true")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ ObserveSafeMode();
+ LOCK2(cs_main, pwallet->cs_wallet);
- return ListReceived(request.params, true);
+ return ListReceived(pwallet, request.params, true);
}
static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
{
- CBitcoinAddress addr;
- if (addr.Set(dest))
- entry.push_back(Pair("address", addr.ToString()));
+ if (IsValidDestination(dest)) {
+ entry.push_back(Pair("address", EncodeDestination(dest)));
+ }
}
-void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)
+/**
+ * List transactions based on the given criteria.
+ *
+ * @param pwallet The wallet.
+ * @param wtx The wallet transaction.
+ * @param strAccount The account, if any, or "*" for all.
+ * @param nMinDepth The minimum confirmation depth.
+ * @param fLong Whether to include the JSON version of the transaction.
+ * @param ret The UniValue into which the result is stored.
+ * @param filter The "is mine" filter bool.
+ */
+void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, const std::string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)
{
CAmount nFee;
- string strSentAccount;
- list<COutputEntry> listReceived;
- list<COutputEntry> listSent;
+ std::string strSentAccount;
+ std::list<COutputEntry> listReceived;
+ std::list<COutputEntry> listSent;
wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter);
- bool fAllAccounts = (strAccount == string("*"));
+ bool fAllAccounts = (strAccount == std::string("*"));
bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
// Sent
if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
{
- BOOST_FOREACH(const COutputEntry& s, listSent)
+ for (const COutputEntry& s : listSent)
{
UniValue entry(UniValue::VOBJ);
- if(involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY))
+ if (involvesWatchonly || (::IsMine(*pwallet, s.destination) & ISMINE_WATCH_ONLY)) {
entry.push_back(Pair("involvesWatchonly", true));
+ }
entry.push_back(Pair("account", strSentAccount));
MaybePushAddress(entry, s.destination);
entry.push_back(Pair("category", "send"));
entry.push_back(Pair("amount", ValueFromAmount(-s.amount)));
- if (pwalletMain->mapAddressBook.count(s.destination))
- entry.push_back(Pair("label", pwalletMain->mapAddressBook[s.destination].name));
+ if (pwallet->mapAddressBook.count(s.destination)) {
+ entry.push_back(Pair("label", pwallet->mapAddressBook[s.destination].name));
+ }
entry.push_back(Pair("vout", s.vout));
entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
if (fLong)
@@ -1370,16 +1558,18 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
// Received
if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
{
- BOOST_FOREACH(const COutputEntry& r, listReceived)
+ for (const COutputEntry& r : listReceived)
{
- string account;
- if (pwalletMain->mapAddressBook.count(r.destination))
- account = pwalletMain->mapAddressBook[r.destination].name;
+ std::string account;
+ if (pwallet->mapAddressBook.count(r.destination)) {
+ account = pwallet->mapAddressBook[r.destination].name;
+ }
if (fAllAccounts || (account == strAccount))
{
UniValue entry(UniValue::VOBJ);
- if(involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY))
+ if (involvesWatchonly || (::IsMine(*pwallet, r.destination) & ISMINE_WATCH_ONLY)) {
entry.push_back(Pair("involvesWatchonly", true));
+ }
entry.push_back(Pair("account", account));
MaybePushAddress(entry, r.destination);
if (wtx.IsCoinBase())
@@ -1396,8 +1586,9 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
entry.push_back(Pair("category", "receive"));
}
entry.push_back(Pair("amount", ValueFromAmount(r.amount)));
- if (pwalletMain->mapAddressBook.count(r.destination))
+ if (pwallet->mapAddressBook.count(r.destination)) {
entry.push_back(Pair("label", account));
+ }
entry.push_back(Pair("vout", r.vout));
if (fLong)
WalletTxToJSON(wtx, entry);
@@ -1407,9 +1598,9 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
}
}
-void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, UniValue& ret)
+void AcentryToJSON(const CAccountingEntry& acentry, const std::string& strAccount, UniValue& ret)
{
- bool fAllAccounts = (strAccount == string("*"));
+ bool fAllAccounts = (strAccount == std::string("*"));
if (fAllAccounts || acentry.strAccount == strAccount)
{
@@ -1426,11 +1617,13 @@ void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Un
UniValue listtransactions(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() > 4)
- throw runtime_error(
+ throw std::runtime_error(
"listtransactions ( \"account\" count skip include_watchonly)\n"
"\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
"\nArguments:\n"
@@ -1489,19 +1682,20 @@ UniValue listtransactions(const JSONRPCRequest& request)
+ HelpExampleRpc("listtransactions", "\"*\", 20, 100")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ ObserveSafeMode();
+ LOCK2(cs_main, pwallet->cs_wallet);
- string strAccount = "*";
- if (request.params.size() > 0)
+ std::string strAccount = "*";
+ if (!request.params[0].isNull())
strAccount = request.params[0].get_str();
int nCount = 10;
- if (request.params.size() > 1)
+ if (!request.params[1].isNull())
nCount = request.params[1].get_int();
int nFrom = 0;
- if (request.params.size() > 2)
+ if (!request.params[2].isNull())
nFrom = request.params[2].get_int();
isminefilter filter = ISMINE_SPENDABLE;
- if(request.params.size() > 3)
+ if(!request.params[3].isNull())
if(request.params[3].get_bool())
filter = filter | ISMINE_WATCH_ONLY;
@@ -1512,16 +1706,16 @@ UniValue listtransactions(const JSONRPCRequest& request)
UniValue ret(UniValue::VARR);
- const CWallet::TxItems & txOrdered = pwalletMain->wtxOrdered;
+ const CWallet::TxItems & txOrdered = pwallet->wtxOrdered;
// iterate backwards until we have nCount items to return:
for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
{
CWalletTx *const pwtx = (*it).second.first;
- if (pwtx != 0)
- ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
+ if (pwtx != nullptr)
+ ListTransactions(pwallet, *pwtx, strAccount, 0, true, ret, filter);
CAccountingEntry *const pacentry = (*it).second.second;
- if (pacentry != 0)
+ if (pacentry != nullptr)
AcentryToJSON(*pacentry, strAccount, ret);
if ((int)ret.size() >= (nCount+nFrom)) break;
@@ -1533,11 +1727,11 @@ UniValue listtransactions(const JSONRPCRequest& request)
if ((nFrom + nCount) > (int)ret.size())
nCount = ret.size() - nFrom;
- vector<UniValue> arrTmp = ret.getValues();
+ std::vector<UniValue> arrTmp = ret.getValues();
- vector<UniValue>::iterator first = arrTmp.begin();
+ std::vector<UniValue>::iterator first = arrTmp.begin();
std::advance(first, nFrom);
- vector<UniValue>::iterator last = arrTmp.begin();
+ std::vector<UniValue>::iterator last = arrTmp.begin();
std::advance(last, nFrom+nCount);
if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end());
@@ -1554,11 +1748,13 @@ UniValue listtransactions(const JSONRPCRequest& request)
UniValue listaccounts(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"listaccounts ( minconf include_watchonly)\n"
"\nDEPRECATED. Returns Object that has account names as keys, account balances as values.\n"
"\nArguments:\n"
@@ -1580,52 +1776,54 @@ UniValue listaccounts(const JSONRPCRequest& request)
+ HelpExampleRpc("listaccounts", "6")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ ObserveSafeMode();
+ LOCK2(cs_main, pwallet->cs_wallet);
int nMinDepth = 1;
- if (request.params.size() > 0)
+ if (!request.params[0].isNull())
nMinDepth = request.params[0].get_int();
isminefilter includeWatchonly = ISMINE_SPENDABLE;
- if(request.params.size() > 1)
+ if(!request.params[1].isNull())
if(request.params[1].get_bool())
includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
- map<string, CAmount> mapAccountBalances;
- BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& entry, pwalletMain->mapAddressBook) {
- if (IsMine(*pwalletMain, entry.first) & includeWatchonly) // This address belongs to me
+ std::map<std::string, CAmount> mapAccountBalances;
+ for (const std::pair<CTxDestination, CAddressBookData>& entry : pwallet->mapAddressBook) {
+ if (IsMine(*pwallet, entry.first) & includeWatchonly) { // This address belongs to me
mapAccountBalances[entry.second.name] = 0;
+ }
}
- for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
- {
- const CWalletTx& wtx = (*it).second;
+ for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
+ const CWalletTx& wtx = pairWtx.second;
CAmount nFee;
- string strSentAccount;
- list<COutputEntry> listReceived;
- list<COutputEntry> listSent;
+ std::string strSentAccount;
+ std::list<COutputEntry> listReceived;
+ std::list<COutputEntry> listSent;
int nDepth = wtx.GetDepthInMainChain();
if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0)
continue;
wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly);
mapAccountBalances[strSentAccount] -= nFee;
- BOOST_FOREACH(const COutputEntry& s, listSent)
+ for (const COutputEntry& s : listSent)
mapAccountBalances[strSentAccount] -= s.amount;
if (nDepth >= nMinDepth)
{
- BOOST_FOREACH(const COutputEntry& r, listReceived)
- if (pwalletMain->mapAddressBook.count(r.destination))
- mapAccountBalances[pwalletMain->mapAddressBook[r.destination].name] += r.amount;
+ for (const COutputEntry& r : listReceived)
+ if (pwallet->mapAddressBook.count(r.destination)) {
+ mapAccountBalances[pwallet->mapAddressBook[r.destination].name] += r.amount;
+ }
else
mapAccountBalances[""] += r.amount;
}
}
- const list<CAccountingEntry> & acentries = pwalletMain->laccentries;
- BOOST_FOREACH(const CAccountingEntry& entry, acentries)
+ const std::list<CAccountingEntry>& acentries = pwallet->laccentries;
+ for (const CAccountingEntry& entry : acentries)
mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
UniValue ret(UniValue::VOBJ);
- BOOST_FOREACH(const PAIRTYPE(string, CAmount)& accountBalance, mapAccountBalances) {
+ for (const std::pair<std::string, CAmount>& accountBalance : mapAccountBalances) {
ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
}
return ret;
@@ -1633,17 +1831,23 @@ UniValue listaccounts(const JSONRPCRequest& request)
UniValue listsinceblock(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (request.fHelp)
- throw runtime_error(
- "listsinceblock ( \"blockhash\" target_confirmations include_watchonly)\n"
- "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n"
+ if (request.fHelp || request.params.size() > 4)
+ throw std::runtime_error(
+ "listsinceblock ( \"blockhash\" target_confirmations include_watchonly include_removed )\n"
+ "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted.\n"
+ "If \"blockhash\" is no longer a part of the main chain, transactions from the fork point onward are included.\n"
+ "Additionally, if include_removed is set, transactions affecting the wallet which were removed are returned in the \"removed\" array.\n"
"\nArguments:\n"
"1. \"blockhash\" (string, optional) The block hash to list transactions since\n"
- "2. target_confirmations: (numeric, optional) The confirmations required, must be 1 or more\n"
- "3. include_watchonly: (bool, optional, default=false) Include transactions to watch-only addresses (see 'importaddress')"
+ "2. target_confirmations: (numeric, optional, default=1) Return the nth block hash from the main chain. e.g. 1 would mean the best block hash. Note: this is not used as a filter, but only affects [lastblock] in the return value\n"
+ "3. include_watchonly: (bool, optional, default=false) Include transactions to watch-only addresses (see 'importaddress')\n"
+ "4. include_removed: (bool, optional, default=true) Show transactions that were removed due to a reorg in the \"removed\" array\n"
+ " (not guaranteed to work on pruned nodes)\n"
"\nResult:\n"
"{\n"
" \"transactions\": [\n"
@@ -1668,8 +1872,12 @@ UniValue listsinceblock(const JSONRPCRequest& request)
" \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
" \"label\" : \"label\" (string) A comment for the address/transaction, if any\n"
" \"to\": \"...\", (string) If a comment to is associated with the transaction.\n"
- " ],\n"
- " \"lastblock\": \"lastblockhash\" (string) The hash of the last block\n"
+ " ],\n"
+ " \"removed\": [\n"
+ " <structure is the same as \"transactions\" above, only present if include_removed=true>\n"
+ " Note: transactions that were readded in the active chain will appear as-is in this array, and may thus have a positive confirmation count.\n"
+ " ],\n"
+ " \"lastblock\": \"lastblockhash\" (string) The hash of the block (target_confirmations-1) from the best block on the main chain. This is typically used to feed back into listsinceblock the next time you call it. So you would generally use a target_confirmations of say 6, so you will be continually re-notified of transactions until they've reached 6 confirmations plus any new ones\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("listsinceblock", "")
@@ -1677,44 +1885,73 @@ UniValue listsinceblock(const JSONRPCRequest& request)
+ HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ ObserveSafeMode();
+ LOCK2(cs_main, pwallet->cs_wallet);
- CBlockIndex *pindex = NULL;
+ const CBlockIndex* pindex = nullptr; // Block index of the specified block or the common ancestor, if the block provided was in a deactivated chain.
+ const CBlockIndex* paltindex = nullptr; // Block index of the specified block, even if it's in a deactivated chain.
int target_confirms = 1;
isminefilter filter = ISMINE_SPENDABLE;
- if (request.params.size() > 0)
- {
+ if (!request.params[0].isNull()) {
uint256 blockId;
blockId.SetHex(request.params[0].get_str());
BlockMap::iterator it = mapBlockIndex.find(blockId);
- if (it != mapBlockIndex.end())
- pindex = it->second;
+ if (it != mapBlockIndex.end()) {
+ paltindex = pindex = it->second;
+ if (chainActive[pindex->nHeight] != pindex) {
+ // the block being asked for is a part of a deactivated chain;
+ // we don't want to depend on its perceived height in the block
+ // chain, we want to instead use the last common ancestor
+ pindex = chainActive.FindFork(pindex);
+ }
+ }
}
- if (request.params.size() > 1)
- {
+ if (!request.params[1].isNull()) {
target_confirms = request.params[1].get_int();
- if (target_confirms < 1)
+ if (target_confirms < 1) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
+ }
}
- if(request.params.size() > 2)
- if(request.params[2].get_bool())
- filter = filter | ISMINE_WATCH_ONLY;
+ if (!request.params[2].isNull() && request.params[2].get_bool()) {
+ filter = filter | ISMINE_WATCH_ONLY;
+ }
+
+ bool include_removed = (request.params[3].isNull() || request.params[3].get_bool());
int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
UniValue transactions(UniValue::VARR);
- for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
- {
- CWalletTx tx = (*it).second;
+ for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
+ CWalletTx tx = pairWtx.second;
- if (depth == -1 || tx.GetDepthInMainChain() < depth)
- ListTransactions(tx, "*", 0, true, transactions, filter);
+ if (depth == -1 || tx.GetDepthInMainChain() < depth) {
+ ListTransactions(pwallet, tx, "*", 0, true, transactions, filter);
+ }
+ }
+
+ // when a reorg'd block is requested, we also list any relevant transactions
+ // in the blocks of the chain that was detached
+ UniValue removed(UniValue::VARR);
+ while (include_removed && paltindex && paltindex != pindex) {
+ CBlock block;
+ if (!ReadBlockFromDisk(block, paltindex, Params().GetConsensus())) {
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
+ }
+ for (const CTransactionRef& tx : block.vtx) {
+ auto it = pwallet->mapWallet.find(tx->GetHash());
+ if (it != pwallet->mapWallet.end()) {
+ // We want all transactions regardless of confirmation count to appear here,
+ // even negative confirmation ones, hence the big negative.
+ ListTransactions(pwallet, it->second, "*", -100000000, true, removed, filter);
+ }
+ }
+ paltindex = paltindex->pprev;
}
CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
@@ -1722,6 +1959,7 @@ UniValue listsinceblock(const JSONRPCRequest& request)
UniValue ret(UniValue::VOBJ);
ret.push_back(Pair("transactions", transactions));
+ if (include_removed) ret.push_back(Pair("removed", removed));
ret.push_back(Pair("lastblock", lastblock.GetHex()));
return ret;
@@ -1729,11 +1967,13 @@ UniValue listsinceblock(const JSONRPCRequest& request)
UniValue gettransaction(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"gettransaction \"txid\" ( include_watchonly )\n"
"\nGet detailed information about in-wallet transaction <txid>\n"
"\nArguments:\n"
@@ -1764,7 +2004,7 @@ UniValue gettransaction(const JSONRPCRequest& request)
" \"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"
" \"abandoned\": xxx (bool) 'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n"
- " 'send' category of transactions.\n"
+ " 'send' category of transactions.\n"
" }\n"
" ,...\n"
" ],\n"
@@ -1777,20 +2017,23 @@ UniValue gettransaction(const JSONRPCRequest& request)
+ HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ ObserveSafeMode();
+ LOCK2(cs_main, pwallet->cs_wallet);
uint256 hash;
hash.SetHex(request.params[0].get_str());
isminefilter filter = ISMINE_SPENDABLE;
- if(request.params.size() > 1)
+ if(!request.params[1].isNull())
if(request.params[1].get_bool())
filter = filter | ISMINE_WATCH_ONLY;
UniValue entry(UniValue::VOBJ);
- if (!pwalletMain->mapWallet.count(hash))
+ auto it = pwallet->mapWallet.find(hash);
+ if (it == pwallet->mapWallet.end()) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
- const CWalletTx& wtx = pwalletMain->mapWallet[hash];
+ }
+ const CWalletTx& wtx = it->second;
CAmount nCredit = wtx.GetCredit(filter);
CAmount nDebit = wtx.GetDebit(filter);
@@ -1804,10 +2047,10 @@ UniValue gettransaction(const JSONRPCRequest& request)
WalletTxToJSON(wtx, entry);
UniValue details(UniValue::VARR);
- ListTransactions(wtx, "*", 0, false, details, filter);
+ ListTransactions(pwallet, wtx, "*", 0, false, details, filter);
entry.push_back(Pair("details", details));
- string strHex = EncodeHexTx(static_cast<CTransaction>(wtx), RPCSerializationFlags());
+ std::string strHex = EncodeHexTx(static_cast<CTransaction>(wtx), RPCSerializationFlags());
entry.push_back(Pair("hex", strHex));
return entry;
@@ -1815,11 +2058,13 @@ UniValue gettransaction(const JSONRPCRequest& request)
UniValue abandontransaction(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"abandontransaction \"txid\"\n"
"\nMark in-wallet transaction <txid> as abandoned\n"
"This will mark this transaction and all its in-wallet descendants as abandoned which will allow\n"
@@ -1834,15 +2079,18 @@ UniValue abandontransaction(const JSONRPCRequest& request)
+ HelpExampleRpc("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ ObserveSafeMode();
+ LOCK2(cs_main, pwallet->cs_wallet);
uint256 hash;
hash.SetHex(request.params[0].get_str());
- if (!pwalletMain->mapWallet.count(hash))
+ if (!pwallet->mapWallet.count(hash)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
- if (!pwalletMain->AbandonTransaction(hash))
+ }
+ if (!pwallet->AbandonTransaction(hash)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not eligible for abandonment");
+ }
return NullUniValue;
}
@@ -1850,11 +2098,13 @@ UniValue abandontransaction(const JSONRPCRequest& request)
UniValue backupwallet(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"backupwallet \"destination\"\n"
"\nSafely copies current wallet file to destination, which can be a directory or a path with filename.\n"
"\nArguments:\n"
@@ -1864,11 +2114,12 @@ UniValue backupwallet(const JSONRPCRequest& request)
+ HelpExampleRpc("backupwallet", "\"backup.dat\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- string strDest = request.params[0].get_str();
- if (!pwalletMain->BackupWallet(strDest))
+ std::string strDest = request.params[0].get_str();
+ if (!pwallet->BackupWallet(strDest)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
+ }
return NullUniValue;
}
@@ -1876,14 +2127,16 @@ UniValue backupwallet(const JSONRPCRequest& request)
UniValue keypoolrefill(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() > 1)
- throw runtime_error(
+ throw std::runtime_error(
"keypoolrefill ( newsize )\n"
"\nFills the keypool."
- + HelpRequiringPassphrase() + "\n"
+ + HelpRequiringPassphrase(pwallet) + "\n"
"\nArguments\n"
"1. newsize (numeric, optional, default=100) The new keypool size\n"
"\nExamples:\n"
@@ -1891,21 +2144,22 @@ UniValue keypoolrefill(const JSONRPCRequest& request)
+ HelpExampleRpc("keypoolrefill", "")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
// 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
unsigned int kpSize = 0;
- if (request.params.size() > 0) {
+ if (!request.params[0].isNull()) {
if (request.params[0].get_int() < 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
kpSize = (unsigned int)request.params[0].get_int();
}
- EnsureWalletIsUnlocked();
- pwalletMain->TopUpKeyPool(kpSize);
+ EnsureWalletIsUnlocked(pwallet);
+ pwallet->TopUpKeyPool(kpSize);
- if (pwalletMain->GetKeyPoolSize() < kpSize)
+ if (pwallet->GetKeyPoolSize() < kpSize) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
+ }
return NullUniValue;
}
@@ -1913,18 +2167,20 @@ UniValue keypoolrefill(const JSONRPCRequest& request)
static void LockWallet(CWallet* pWallet)
{
- LOCK(cs_nWalletUnlockTime);
- nWalletUnlockTime = 0;
+ LOCK(pWallet->cs_wallet);
+ pWallet->nRelockTime = 0;
pWallet->Lock();
}
UniValue walletpassphrase(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (pwalletMain->IsCrypted() && (request.fHelp || request.params.size() != 2))
- throw runtime_error(
+ if (pwallet->IsCrypted() && (request.fHelp || request.params.size() != 2)) {
+ throw std::runtime_error(
"walletpassphrase \"passphrase\" timeout\n"
"\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
"This is needed prior to performing transactions related to private keys such as sending bitcoins\n"
@@ -1935,20 +2191,22 @@ UniValue walletpassphrase(const JSONRPCRequest& request)
"Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
"time that overrides the old one.\n"
"\nExamples:\n"
- "\nunlock the wallet for 60 seconds\n"
+ "\nUnlock the wallet for 60 seconds\n"
+ HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
"\nLock the wallet again (before 60 seconds)\n"
+ HelpExampleCli("walletlock", "") +
"\nAs json rpc call\n"
+ HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
);
+ }
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
if (request.fHelp)
return true;
- if (!pwalletMain->IsCrypted())
+ if (!pwallet->IsCrypted()) {
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
+ }
// Note that the walletpassphrase is stored in request.params[0] which is not mlock()ed
SecureString strWalletPass;
@@ -1959,20 +2217,20 @@ UniValue walletpassphrase(const JSONRPCRequest& request)
if (strWalletPass.length() > 0)
{
- if (!pwalletMain->Unlock(strWalletPass))
+ if (!pwallet->Unlock(strWalletPass)) {
throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
+ }
}
else
- throw runtime_error(
+ throw std::runtime_error(
"walletpassphrase <passphrase> <timeout>\n"
"Stores the wallet decryption key in memory for <timeout> seconds.");
- pwalletMain->TopUpKeyPool();
+ pwallet->TopUpKeyPool();
int64_t nSleepTime = request.params[1].get_int64();
- LOCK(cs_nWalletUnlockTime);
- nWalletUnlockTime = GetTime() + nSleepTime;
- RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
+ pwallet->nRelockTime = GetTime() + nSleepTime;
+ RPCRunLater(strprintf("lockwallet(%s)", pwallet->GetName()), boost::bind(LockWallet, pwallet), nSleepTime);
return NullUniValue;
}
@@ -1980,11 +2238,13 @@ UniValue walletpassphrase(const JSONRPCRequest& request)
UniValue walletpassphrasechange(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (pwalletMain->IsCrypted() && (request.fHelp || request.params.size() != 2))
- throw runtime_error(
+ if (pwallet->IsCrypted() && (request.fHelp || request.params.size() != 2)) {
+ throw std::runtime_error(
"walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
"\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n"
"\nArguments:\n"
@@ -1994,13 +2254,15 @@ UniValue walletpassphrasechange(const JSONRPCRequest& request)
+ HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
+ HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
);
+ }
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
if (request.fHelp)
return true;
- if (!pwalletMain->IsCrypted())
+ if (!pwallet->IsCrypted()) {
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
+ }
// TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
// Alternately, find a way to make request.params[0] mlock()'d to begin with.
@@ -2013,12 +2275,13 @@ UniValue walletpassphrasechange(const JSONRPCRequest& request)
strNewWalletPass = request.params[1].get_str().c_str();
if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
- throw runtime_error(
+ throw std::runtime_error(
"walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
"Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
- if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
+ if (!pwallet->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass)) {
throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
+ }
return NullUniValue;
}
@@ -2026,11 +2289,13 @@ UniValue walletpassphrasechange(const JSONRPCRequest& request)
UniValue walletlock(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (pwalletMain->IsCrypted() && (request.fHelp || request.params.size() != 0))
- throw runtime_error(
+ if (pwallet->IsCrypted() && (request.fHelp || request.params.size() != 0)) {
+ throw std::runtime_error(
"walletlock\n"
"\nRemoves the wallet encryption key from memory, locking the wallet.\n"
"After calling this method, you will need to call walletpassphrase again\n"
@@ -2045,31 +2310,32 @@ UniValue walletlock(const JSONRPCRequest& request)
"\nAs json rpc call\n"
+ HelpExampleRpc("walletlock", "")
);
+ }
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
if (request.fHelp)
return true;
- if (!pwalletMain->IsCrypted())
+ if (!pwallet->IsCrypted()) {
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
-
- {
- LOCK(cs_nWalletUnlockTime);
- pwalletMain->Lock();
- nWalletUnlockTime = 0;
}
+ pwallet->Lock();
+ pwallet->nRelockTime = 0;
+
return NullUniValue;
}
UniValue encryptwallet(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (!pwalletMain->IsCrypted() && (request.fHelp || request.params.size() != 1))
- throw runtime_error(
+ if (!pwallet->IsCrypted() && (request.fHelp || request.params.size() != 1)) {
+ throw std::runtime_error(
"encryptwallet \"passphrase\"\n"
"\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
"After this, any calls that interact with private keys such as sending or signing \n"
@@ -2080,24 +2346,26 @@ UniValue encryptwallet(const JSONRPCRequest& request)
"\nArguments:\n"
"1. \"passphrase\" (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\n"
"\nExamples:\n"
- "\nEncrypt you wallet\n"
+ "\nEncrypt your wallet\n"
+ HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
"\nNow set the passphrase to use the wallet, such as for signing or sending bitcoin\n"
+ HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
- "\nNow we can so something like sign\n"
+ "\nNow we can do something like sign\n"
+ HelpExampleCli("signmessage", "\"address\" \"test message\"") +
"\nNow lock the wallet again by removing the passphrase\n"
+ HelpExampleCli("walletlock", "") +
"\nAs a json rpc call\n"
+ HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
);
+ }
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
if (request.fHelp)
return true;
- if (pwalletMain->IsCrypted())
+ if (pwallet->IsCrypted()) {
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
+ }
// TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
// Alternately, find a way to make request.params[0] mlock()'d to begin with.
@@ -2106,12 +2374,13 @@ UniValue encryptwallet(const JSONRPCRequest& request)
strWalletPass = request.params[0].get_str().c_str();
if (strWalletPass.length() < 1)
- throw runtime_error(
+ throw std::runtime_error(
"encryptwallet <passphrase>\n"
"Encrypts the wallet with <passphrase>.");
- if (!pwalletMain->EncryptWallet(strWalletPass))
+ if (!pwallet->EncryptWallet(strWalletPass)) {
throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
+ }
// BDB seems to have a bad habit of writing old data into
// slack space in .dat files; that is bad if the old data is
@@ -2122,11 +2391,13 @@ UniValue encryptwallet(const JSONRPCRequest& request)
UniValue lockunspent(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"lockunspent unlock ([{\"txid\":\"txid\",\"vout\":n},...])\n"
"\nUpdates list of temporarily unspendable outputs.\n"
"Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
@@ -2162,21 +2433,20 @@ UniValue lockunspent(const JSONRPCRequest& request)
+ HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- if (request.params.size() == 1)
- RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VBOOL));
- else
- RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VBOOL)(UniValue::VARR));
+ RPCTypeCheckArgument(request.params[0], UniValue::VBOOL);
bool fUnlock = request.params[0].get_bool();
- if (request.params.size() == 1) {
+ if (request.params[1].isNull()) {
if (fUnlock)
- pwalletMain->UnlockAllCoins();
+ pwallet->UnlockAllCoins();
return true;
}
+ RPCTypeCheckArgument(request.params[1], UniValue::VARR);
+
UniValue outputs = request.params[1].get_array();
for (unsigned int idx = 0; idx < outputs.size(); idx++) {
const UniValue& output = outputs[idx];
@@ -2190,7 +2460,7 @@ UniValue lockunspent(const JSONRPCRequest& request)
{"vout", UniValueType(UniValue::VNUM)},
});
- string txid = find_value(o, "txid").get_str();
+ std::string txid = find_value(o, "txid").get_str();
if (!IsHex(txid))
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
@@ -2201,9 +2471,9 @@ UniValue lockunspent(const JSONRPCRequest& request)
COutPoint outpt(uint256S(txid), nOutput);
if (fUnlock)
- pwalletMain->UnlockCoin(outpt);
+ pwallet->UnlockCoin(outpt);
else
- pwalletMain->LockCoin(outpt);
+ pwallet->LockCoin(outpt);
}
return true;
@@ -2211,11 +2481,13 @@ UniValue lockunspent(const JSONRPCRequest& request)
UniValue listlockunspent(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() > 0)
- throw runtime_error(
+ throw std::runtime_error(
"listlockunspent\n"
"\nReturns list of temporarily unspendable outputs.\n"
"See the lockunspent call to lock and unlock transactions for spending.\n"
@@ -2240,14 +2512,15 @@ UniValue listlockunspent(const JSONRPCRequest& request)
+ HelpExampleRpc("listlockunspent", "")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ ObserveSafeMode();
+ LOCK2(cs_main, pwallet->cs_wallet);
- vector<COutPoint> vOutpts;
- pwalletMain->ListLockedCoins(vOutpts);
+ std::vector<COutPoint> vOutpts;
+ pwallet->ListLockedCoins(vOutpts);
UniValue ret(UniValue::VARR);
- BOOST_FOREACH(COutPoint &outpt, vOutpts) {
+ for (COutPoint &outpt : vOutpts) {
UniValue o(UniValue::VOBJ);
o.push_back(Pair("txid", outpt.hash.GetHex()));
@@ -2260,11 +2533,13 @@ UniValue listlockunspent(const JSONRPCRequest& request)
UniValue settxfee(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() < 1 || request.params.size() > 1)
- throw runtime_error(
+ throw std::runtime_error(
"settxfee amount\n"
"\nSet the transaction fee per kB. Overwrites the paytxfee parameter.\n"
"\nArguments:\n"
@@ -2276,7 +2551,7 @@ UniValue settxfee(const JSONRPCRequest& request)
+ HelpExampleRpc("settxfee", "0.00001")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
// Amount
CAmount nAmount = AmountFromValue(request.params[0]);
@@ -2287,72 +2562,124 @@ UniValue settxfee(const JSONRPCRequest& request)
UniValue getwalletinfo(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getwalletinfo\n"
"Returns an object containing various wallet state info.\n"
"\nResult:\n"
"{\n"
- " \"walletversion\": xxxxx, (numeric) the wallet version\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 Unix 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"
- " \"hdmasterkeyid\": \"<hash160>\" (string) the Hash160 of the HD master pubkey\n"
+ " \"walletname\": xxxxx, (string) the wallet name\n"
+ " \"walletversion\": xxxxx, (numeric) the wallet version\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 Unix epoch) of the oldest pre-generated key in the key pool\n"
+ " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated (only counts external keys)\n"
+ " \"keypoolsize_hd_internal\": xxxx, (numeric) how many new keys are pre-generated for internal use (used for change outputs, only appears if the wallet is using this feature, otherwise external keys are used)\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"
+ " \"hdmasterkeyid\": \"<hash160>\" (string) the Hash160 of the HD master pubkey\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getwalletinfo", "")
+ HelpExampleRpc("getwalletinfo", "")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ ObserveSafeMode();
+ LOCK2(cs_main, pwallet->cs_wallet);
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())));
- obj.push_back(Pair("immature_balance", ValueFromAmount(pwalletMain->GetImmatureBalance())));
- obj.push_back(Pair("txcount", (int)pwalletMain->mapWallet.size()));
- obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
- obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
- if (pwalletMain->IsCrypted())
- obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
+
+ size_t kpExternalSize = pwallet->KeypoolCountExternalKeys();
+ obj.push_back(Pair("walletname", pwallet->GetName()));
+ obj.push_back(Pair("walletversion", pwallet->GetVersion()));
+ obj.push_back(Pair("balance", ValueFromAmount(pwallet->GetBalance())));
+ obj.push_back(Pair("unconfirmed_balance", ValueFromAmount(pwallet->GetUnconfirmedBalance())));
+ obj.push_back(Pair("immature_balance", ValueFromAmount(pwallet->GetImmatureBalance())));
+ obj.push_back(Pair("txcount", (int)pwallet->mapWallet.size()));
+ obj.push_back(Pair("keypoololdest", pwallet->GetOldestKeyPoolTime()));
+ obj.push_back(Pair("keypoolsize", (int64_t)kpExternalSize));
+ CKeyID masterKeyID = pwallet->GetHDChain().masterKeyID;
+ if (!masterKeyID.IsNull() && pwallet->CanSupportFeature(FEATURE_HD_SPLIT)) {
+ obj.push_back(Pair("keypoolsize_hd_internal", (int64_t)(pwallet->GetKeyPoolSize() - kpExternalSize)));
+ }
+ if (pwallet->IsCrypted()) {
+ obj.push_back(Pair("unlocked_until", pwallet->nRelockTime));
+ }
obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
- CKeyID masterKeyID = pwalletMain->GetHDChain().masterKeyID;
if (!masterKeyID.IsNull())
obj.push_back(Pair("hdmasterkeyid", masterKeyID.GetHex()));
return obj;
}
+UniValue listwallets(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() != 0)
+ throw std::runtime_error(
+ "listwallets\n"
+ "Returns a list of currently loaded wallets.\n"
+ "For full information on the wallet, use \"getwalletinfo\"\n"
+ "\nResult:\n"
+ "[ (json array of strings)\n"
+ " \"walletname\" (string) the wallet name\n"
+ " ...\n"
+ "]\n"
+ "\nExamples:\n"
+ + HelpExampleCli("listwallets", "")
+ + HelpExampleRpc("listwallets", "")
+ );
+
+ UniValue obj(UniValue::VARR);
+
+ for (CWalletRef pwallet : vpwallets) {
+
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
+ return NullUniValue;
+ }
+
+ LOCK(pwallet->cs_wallet);
+
+ obj.push_back(pwallet->GetName());
+ }
+
+ return obj;
+}
+
UniValue resendwallettransactions(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"resendwallettransactions\n"
"Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
"Intended only for testing; the wallet code periodically re-broadcasts\n"
"automatically.\n"
+ "Returns an RPC error if -walletbroadcast is set to false.\n"
"Returns array of transaction ids that were re-broadcast.\n"
);
if (!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ LOCK2(cs_main, pwallet->cs_wallet);
- std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime(), g_connman.get());
+ if (!pwallet->GetBroadcastTransactions()) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet transaction broadcasting is disabled with -walletbroadcast");
+ }
+
+ std::vector<uint256> txids = pwallet->ResendWalletTransactionsBefore(GetTime(), g_connman.get());
UniValue result(UniValue::VARR);
- BOOST_FOREACH(const uint256& txid, txids)
+ for (const uint256& txid : txids)
{
result.push_back(txid.ToString());
}
@@ -2361,23 +2688,34 @@ UniValue resendwallettransactions(const JSONRPCRequest& request)
UniValue listunspent(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
- if (request.fHelp || request.params.size() > 3)
- throw runtime_error(
- "listunspent ( minconf maxconf [\"addresses\",...] )\n"
+ if (request.fHelp || request.params.size() > 5)
+ throw std::runtime_error(
+ "listunspent ( minconf maxconf [\"addresses\",...] [include_unsafe] [query_options])\n"
"\nReturns array of unspent transaction outputs\n"
"with between minconf and maxconf (inclusive) confirmations.\n"
"Optionally filter to only include txouts paid to specified addresses.\n"
"\nArguments:\n"
"1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
"2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
- "3. \"addresses\" (string) A json array of bitcoin addresses to filter\n"
+ "3. \"addresses\" (string) A json array of bitcoin addresses to filter\n"
" [\n"
- " \"address\" (string) bitcoin address\n"
+ " \"address\" (string) bitcoin address\n"
" ,...\n"
" ]\n"
+ "4. include_unsafe (bool, optional, default=true) Include outputs that are not safe to spend\n"
+ " See description of \"safe\" attribute below.\n"
+ "5. query_options (json, optional) JSON with query options\n"
+ " {\n"
+ " \"minimumAmount\" (numeric or string, default=0) Minimum value of each UTXO in " + CURRENCY_UNIT + "\n"
+ " \"maximumAmount\" (numeric or string, default=unlimited) Maximum value of each UTXO in " + CURRENCY_UNIT + "\n"
+ " \"maximumCount\" (numeric or string, default=unlimited) Maximum number of UTXOs\n"
+ " \"minimumSumAmount\" (numeric or string, default=unlimited) Minimum sum value of all UTXOs in " + CURRENCY_UNIT + "\n"
+ " }\n"
"\nResult\n"
"[ (array of json object)\n"
" {\n"
@@ -2386,11 +2724,14 @@ UniValue listunspent(const JSONRPCRequest& request)
" \"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 " + CURRENCY_UNIT + "\n"
+ " \"amount\" : x.xxx, (numeric) the transaction output amount in " + CURRENCY_UNIT + "\n"
" \"confirmations\" : n, (numeric) The number of confirmations\n"
" \"redeemScript\" : n (string) The redeemScript if scriptPubKey is P2SH\n"
" \"spendable\" : xxx, (bool) Whether we have the private keys to spend this output\n"
- " \"solvable\" : xxx (bool) Whether we know how to spend this output, ignoring the lack of keys\n"
+ " \"solvable\" : xxx, (bool) Whether we know how to spend this output, ignoring the lack of keys\n"
+ " \"safe\" : xxx (bool) Whether this output is considered safe to spend. Unconfirmed transactions\n"
+ " from outside keys and unconfirmed replacement transactions are considered unsafe\n"
+ " and are not eligible for spending by fundrawtransaction and sendtoaddress.\n"
" }\n"
" ,...\n"
"]\n"
@@ -2399,46 +2740,79 @@ UniValue listunspent(const JSONRPCRequest& request)
+ HelpExampleCli("listunspent", "")
+ HelpExampleCli("listunspent", "6 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
+ HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
+ + HelpExampleCli("listunspent", "6 9999999 '[]' true '{ \"minimumAmount\": 0.005 }'")
+ + HelpExampleRpc("listunspent", "6, 9999999, [] , true, { \"minimumAmount\": 0.005 } ")
);
- RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VARR));
+ ObserveSafeMode();
int nMinDepth = 1;
- if (request.params.size() > 0)
+ if (!request.params[0].isNull()) {
+ RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
nMinDepth = request.params[0].get_int();
+ }
int nMaxDepth = 9999999;
- if (request.params.size() > 1)
+ if (!request.params[1].isNull()) {
+ RPCTypeCheckArgument(request.params[1], UniValue::VNUM);
nMaxDepth = request.params[1].get_int();
+ }
- set<CBitcoinAddress> setAddress;
- if (request.params.size() > 2) {
+ std::set<CTxDestination> destinations;
+ if (!request.params[2].isNull()) {
+ RPCTypeCheckArgument(request.params[2], UniValue::VARR);
UniValue inputs = request.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());
- if (setAddress.count(address))
- throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
- setAddress.insert(address);
+ CTxDestination dest = DecodeDestination(input.get_str());
+ if (!IsValidDestination(dest)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + input.get_str());
+ }
+ if (!destinations.insert(dest).second) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + input.get_str());
+ }
}
}
+ bool include_unsafe = true;
+ if (!request.params[3].isNull()) {
+ RPCTypeCheckArgument(request.params[3], UniValue::VBOOL);
+ include_unsafe = request.params[3].get_bool();
+ }
+
+ CAmount nMinimumAmount = 0;
+ CAmount nMaximumAmount = MAX_MONEY;
+ CAmount nMinimumSumAmount = MAX_MONEY;
+ uint64_t nMaximumCount = 0;
+
+ if (!request.params[4].isNull()) {
+ const UniValue& options = request.params[4].get_obj();
+
+ if (options.exists("minimumAmount"))
+ nMinimumAmount = AmountFromValue(options["minimumAmount"]);
+
+ if (options.exists("maximumAmount"))
+ nMaximumAmount = AmountFromValue(options["maximumAmount"]);
+
+ if (options.exists("minimumSumAmount"))
+ nMinimumSumAmount = AmountFromValue(options["minimumSumAmount"]);
+
+ if (options.exists("maximumCount"))
+ nMaximumCount = options["maximumCount"].get_int64();
+ }
+
UniValue results(UniValue::VARR);
- vector<COutput> vecOutputs;
- assert(pwalletMain != NULL);
- LOCK2(cs_main, pwalletMain->cs_wallet);
- pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
- BOOST_FOREACH(const COutput& out, vecOutputs) {
- if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
- continue;
+ std::vector<COutput> vecOutputs;
+ assert(pwallet != nullptr);
+ LOCK2(cs_main, pwallet->cs_wallet);
+ pwallet->AvailableCoins(vecOutputs, !include_unsafe, nullptr, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount, nMinDepth, nMaxDepth);
+ for (const COutput& out : vecOutputs) {
CTxDestination address;
const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
bool fValidAddress = ExtractDestination(scriptPubKey, address);
- if (setAddress.size() && (!fValidAddress || !setAddress.count(address)))
+ if (destinations.size() && (!fValidAddress || !destinations.count(address)))
continue;
UniValue entry(UniValue::VOBJ);
@@ -2446,16 +2820,18 @@ UniValue listunspent(const JSONRPCRequest& request)
entry.push_back(Pair("vout", out.i));
if (fValidAddress) {
- entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
+ entry.push_back(Pair("address", EncodeDestination(address)));
- if (pwalletMain->mapAddressBook.count(address))
- entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
+ if (pwallet->mapAddressBook.count(address)) {
+ entry.push_back(Pair("account", pwallet->mapAddressBook[address].name));
+ }
if (scriptPubKey.IsPayToScriptHash()) {
const CScriptID& hash = boost::get<CScriptID>(address);
CScript redeemScript;
- if (pwalletMain->GetCScript(hash, redeemScript))
+ if (pwallet->GetCScript(hash, redeemScript)) {
entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
+ }
}
}
@@ -2464,6 +2840,7 @@ UniValue listunspent(const JSONRPCRequest& request)
entry.push_back(Pair("confirmations", out.nDepth));
entry.push_back(Pair("spendable", out.fSpendable));
entry.push_back(Pair("solvable", out.fSolvable));
+ entry.push_back(Pair("safe", out.fSafe));
results.push_back(entry);
}
@@ -2472,11 +2849,13 @@ UniValue listunspent(const JSONRPCRequest& request)
UniValue fundrawtransaction(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(request.fHelp))
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
+ }
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"fundrawtransaction \"hexstring\" ( options )\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 at most one change output to the outputs.\n"
@@ -2496,13 +2875,20 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
" \"changePosition\" (numeric, optional, default random) The index of the change output\n"
" \"includeWatching\" (boolean, optional, default false) Also select inputs which are watch only\n"
" \"lockUnspents\" (boolean, optional, default false) Lock selected unspent outputs\n"
- " \"feeRate\" (numeric, optional, default not set: makes wallet determine the fee) Set a specific feerate (" + CURRENCY_UNIT + " per KB)\n"
+ " \"feeRate\" (numeric, optional, default not set: makes wallet determine the fee) Set a specific fee rate in " + CURRENCY_UNIT + "/kB\n"
" \"subtractFeeFromOutputs\" (array, optional) A json array of integers.\n"
" The fee will be equally deducted from the amount of each specified output.\n"
" The outputs are specified by their zero-based index, before any change output is added.\n"
" Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
" If no outputs are specified here, the sender pays the fee.\n"
" [vout_index,...]\n"
+ " \"replaceable\" (boolean, optional) Marks this transaction as BIP125 replaceable.\n"
+ " Allows this transaction to be replaced by a transaction with higher fees\n"
+ " \"conf_target\" (numeric, optional) Confirmation target (in blocks)\n"
+ " \"estimate_mode\" (string, optional, default=UNSET) The fee estimate mode, must be one of:\n"
+ " \"UNSET\"\n"
+ " \"ECONOMICAL\"\n"
+ " \"CONSERVATIVE\"\n"
" }\n"
" for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}\n"
"\nResult:\n"
@@ -2522,24 +2908,22 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
+ HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
);
- RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR));
+ ObserveSafeMode();
+ RPCTypeCheck(request.params, {UniValue::VSTR});
- CTxDestination changeAddress = CNoDestination();
+ CCoinControl coinControl;
int changePosition = -1;
- bool includeWatching = false;
bool lockUnspents = false;
- CFeeRate feeRate = CFeeRate(0);
- bool overrideEstimatedFeerate = false;
UniValue subtractFeeFromOutputs;
- set<int> setSubtractFeeFromOutputs;
+ std::set<int> setSubtractFeeFromOutputs;
- if (request.params.size() > 1) {
+ if (!request.params[1].isNull()) {
if (request.params[1].type() == UniValue::VBOOL) {
// backward compatibility bool only fallback
- includeWatching = request.params[1].get_bool();
+ coinControl.fAllowWatchOnly = request.params[1].get_bool();
}
else {
- RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR)(UniValue::VOBJ));
+ RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VOBJ});
UniValue options = request.params[1];
@@ -2549,37 +2933,60 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
{"changePosition", UniValueType(UniValue::VNUM)},
{"includeWatching", UniValueType(UniValue::VBOOL)},
{"lockUnspents", UniValueType(UniValue::VBOOL)},
+ {"reserveChangeKey", UniValueType(UniValue::VBOOL)}, // DEPRECATED (and ignored), should be removed in 0.16 or so.
{"feeRate", UniValueType()}, // will be checked below
{"subtractFeeFromOutputs", UniValueType(UniValue::VARR)},
+ {"replaceable", UniValueType(UniValue::VBOOL)},
+ {"conf_target", UniValueType(UniValue::VNUM)},
+ {"estimate_mode", UniValueType(UniValue::VSTR)},
},
true, true);
if (options.exists("changeAddress")) {
- CBitcoinAddress address(options["changeAddress"].get_str());
+ CTxDestination dest = DecodeDestination(options["changeAddress"].get_str());
- if (!address.IsValid())
- throw JSONRPCError(RPC_INVALID_PARAMETER, "changeAddress must be a valid bitcoin address");
+ if (!IsValidDestination(dest)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "changeAddress must be a valid bitcoin address");
+ }
- changeAddress = address.Get();
+ coinControl.destChange = dest;
}
if (options.exists("changePosition"))
changePosition = options["changePosition"].get_int();
if (options.exists("includeWatching"))
- includeWatching = options["includeWatching"].get_bool();
+ coinControl.fAllowWatchOnly = options["includeWatching"].get_bool();
if (options.exists("lockUnspents"))
lockUnspents = options["lockUnspents"].get_bool();
if (options.exists("feeRate"))
{
- feeRate = CFeeRate(AmountFromValue(options["feeRate"]));
- overrideEstimatedFeerate = true;
+ coinControl.m_feerate = CFeeRate(AmountFromValue(options["feeRate"]));
+ coinControl.fOverrideFeeRate = true;
}
if (options.exists("subtractFeeFromOutputs"))
subtractFeeFromOutputs = options["subtractFeeFromOutputs"].get_array();
+
+ if (options.exists("replaceable")) {
+ coinControl.signalRbf = options["replaceable"].get_bool();
+ }
+ if (options.exists("conf_target")) {
+ if (options.exists("feeRate")) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both conf_target and feeRate");
+ }
+ coinControl.m_confirm_target = ParseConfirmTarget(options["conf_target"]);
+ }
+ if (options.exists("estimate_mode")) {
+ if (options.exists("feeRate")) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both estimate_mode and feeRate");
+ }
+ if (!FeeModeFromString(options["estimate_mode"].get_str(), coinControl.m_fee_mode)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
+ }
+ }
}
}
@@ -2606,10 +3013,11 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
}
CAmount nFeeOut;
- string strFailReason;
+ std::string strFailReason;
- if(!pwalletMain->FundTransaction(tx, nFeeOut, overrideEstimatedFeerate, feeRate, changePosition, strFailReason, includeWatching, lockUnspents, setSubtractFeeFromOutputs, changeAddress))
- throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason);
+ if (!pwallet->FundTransaction(tx, nFeeOut, changePosition, strFailReason, lockUnspents, setSubtractFeeFromOutputs, coinControl)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, strFailReason);
+ }
UniValue result(UniValue::VOBJ);
result.push_back(Pair("hex", EncodeHexTx(tx)));
@@ -2619,6 +3027,192 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
return result;
}
+UniValue bumpfee(const JSONRPCRequest& request)
+{
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
+ return NullUniValue;
+
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
+ throw std::runtime_error(
+ "bumpfee \"txid\" ( options ) \n"
+ "\nBumps the fee of an opt-in-RBF transaction T, replacing it with a new transaction B.\n"
+ "An opt-in RBF transaction with the given txid must be in the wallet.\n"
+ "The command will pay the additional fee by decreasing (or perhaps removing) its change output.\n"
+ "If the change output is not big enough to cover the increased fee, the command will currently fail\n"
+ "instead of adding new inputs to compensate. (A future implementation could improve this.)\n"
+ "The command will fail if the wallet or mempool contains a transaction that spends one of T's outputs.\n"
+ "By default, the new fee will be calculated automatically using estimatefee.\n"
+ "The user can specify a confirmation target for estimatefee.\n"
+ "Alternatively, the user can specify totalFee, or use RPC settxfee to set a higher fee rate.\n"
+ "At a minimum, the new fee rate must be high enough to pay an additional new relay fee (incrementalfee\n"
+ "returned by getnetworkinfo) to enter the node's mempool.\n"
+ "\nArguments:\n"
+ "1. txid (string, required) The txid to be bumped\n"
+ "2. options (object, optional)\n"
+ " {\n"
+ " \"confTarget\" (numeric, optional) Confirmation target (in blocks)\n"
+ " \"totalFee\" (numeric, optional) Total fee (NOT feerate) to pay, in satoshis.\n"
+ " In rare cases, the actual fee paid might be slightly higher than the specified\n"
+ " totalFee if the tx change output has to be removed because it is too close to\n"
+ " the dust threshold.\n"
+ " \"replaceable\" (boolean, optional, default true) Whether the new transaction should still be\n"
+ " marked bip-125 replaceable. If true, the sequence numbers in the transaction will\n"
+ " be left unchanged from the original. If false, any input sequence numbers in the\n"
+ " original transaction that were less than 0xfffffffe will be increased to 0xfffffffe\n"
+ " so the new transaction will not be explicitly bip-125 replaceable (though it may\n"
+ " still be replaceable in practice, for example if it has unconfirmed ancestors which\n"
+ " are replaceable).\n"
+ " \"estimate_mode\" (string, optional, default=UNSET) The fee estimate mode, must be one of:\n"
+ " \"UNSET\"\n"
+ " \"ECONOMICAL\"\n"
+ " \"CONSERVATIVE\"\n"
+ " }\n"
+ "\nResult:\n"
+ "{\n"
+ " \"txid\": \"value\", (string) The id of the new transaction\n"
+ " \"origfee\": n, (numeric) Fee of the replaced transaction\n"
+ " \"fee\": n, (numeric) Fee of the new transaction\n"
+ " \"errors\": [ str... ] (json array of strings) Errors encountered during processing (may be empty)\n"
+ "}\n"
+ "\nExamples:\n"
+ "\nBump the fee, get the new transaction\'s txid\n" +
+ HelpExampleCli("bumpfee", "<txid>"));
+ }
+
+ RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VOBJ});
+ uint256 hash;
+ hash.SetHex(request.params[0].get_str());
+
+ // optional parameters
+ CAmount totalFee = 0;
+ CCoinControl coin_control;
+ coin_control.signalRbf = true;
+ if (!request.params[1].isNull()) {
+ UniValue options = request.params[1];
+ RPCTypeCheckObj(options,
+ {
+ {"confTarget", UniValueType(UniValue::VNUM)},
+ {"totalFee", UniValueType(UniValue::VNUM)},
+ {"replaceable", UniValueType(UniValue::VBOOL)},
+ {"estimate_mode", UniValueType(UniValue::VSTR)},
+ },
+ true, true);
+
+ if (options.exists("confTarget") && options.exists("totalFee")) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "confTarget and totalFee options should not both be set. Please provide either a confirmation target for fee estimation or an explicit total fee for the transaction.");
+ } else if (options.exists("confTarget")) { // TODO: alias this to conf_target
+ coin_control.m_confirm_target = ParseConfirmTarget(options["confTarget"]);
+ } else if (options.exists("totalFee")) {
+ totalFee = options["totalFee"].get_int64();
+ if (totalFee <= 0) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid totalFee %s (must be greater than 0)", FormatMoney(totalFee)));
+ }
+ }
+
+ if (options.exists("replaceable")) {
+ coin_control.signalRbf = options["replaceable"].get_bool();
+ }
+ if (options.exists("estimate_mode")) {
+ if (!FeeModeFromString(options["estimate_mode"].get_str(), coin_control.m_fee_mode)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
+ }
+ }
+ }
+
+ LOCK2(cs_main, pwallet->cs_wallet);
+ EnsureWalletIsUnlocked(pwallet);
+
+ CFeeBumper feeBump(pwallet, hash, coin_control, totalFee);
+ BumpFeeResult res = feeBump.getResult();
+ if (res != BumpFeeResult::OK)
+ {
+ switch(res) {
+ case BumpFeeResult::INVALID_ADDRESS_OR_KEY:
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, feeBump.getErrors()[0]);
+ break;
+ case BumpFeeResult::INVALID_REQUEST:
+ throw JSONRPCError(RPC_INVALID_REQUEST, feeBump.getErrors()[0]);
+ break;
+ case BumpFeeResult::INVALID_PARAMETER:
+ throw JSONRPCError(RPC_INVALID_PARAMETER, feeBump.getErrors()[0]);
+ break;
+ case BumpFeeResult::WALLET_ERROR:
+ throw JSONRPCError(RPC_WALLET_ERROR, feeBump.getErrors()[0]);
+ break;
+ default:
+ throw JSONRPCError(RPC_MISC_ERROR, feeBump.getErrors()[0]);
+ break;
+ }
+ }
+
+ // sign bumped transaction
+ if (!feeBump.signTransaction(pwallet)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Can't sign transaction.");
+ }
+ // commit the bumped transaction
+ if(!feeBump.commit(pwallet)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, feeBump.getErrors()[0]);
+ }
+ UniValue result(UniValue::VOBJ);
+ result.push_back(Pair("txid", feeBump.getBumpedTxId().GetHex()));
+ result.push_back(Pair("origfee", ValueFromAmount(feeBump.getOldFee())));
+ result.push_back(Pair("fee", ValueFromAmount(feeBump.getNewFee())));
+ UniValue errors(UniValue::VARR);
+ for (const std::string& err: feeBump.getErrors())
+ errors.push_back(err);
+ result.push_back(Pair("errors", errors));
+
+ return result;
+}
+
+UniValue generate(const JSONRPCRequest& request)
+{
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
+ return NullUniValue;
+ }
+
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
+ throw std::runtime_error(
+ "generate nblocks ( maxtries )\n"
+ "\nMine up to nblocks blocks immediately (before the RPC call returns) to an address in the wallet.\n"
+ "\nArguments:\n"
+ "1. nblocks (numeric, required) How many blocks are generated immediately.\n"
+ "2. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n"
+ "\nResult:\n"
+ "[ blockhashes ] (array) hashes of blocks generated\n"
+ "\nExamples:\n"
+ "\nGenerate 11 blocks\n"
+ + HelpExampleCli("generate", "11")
+ );
+ }
+
+ int num_generate = request.params[0].get_int();
+ uint64_t max_tries = 1000000;
+ if (!request.params[1].isNull()) {
+ max_tries = request.params[1].get_int();
+ }
+
+ std::shared_ptr<CReserveScript> coinbase_script;
+ pwallet->GetScriptForMining(coinbase_script);
+
+ // If the keypool is exhausted, no script is returned at all. Catch this.
+ if (!coinbase_script) {
+ throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
+ }
+
+ //throw an error if no script was provided
+ if (coinbase_script->reserveScript.empty()) {
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available");
+ }
+
+ return generateBlocks(coinbase_script, num_generate, max_tries, true);
+}
+
+extern UniValue abortrescan(const JSONRPCRequest& request); // in rpcdump.cpp
extern UniValue dumpprivkey(const JSONRPCRequest& request); // in rpcdump.cpp
extern UniValue importprivkey(const JSONRPCRequest& request);
extern UniValue importaddress(const JSONRPCRequest& request);
@@ -2630,62 +3224,64 @@ extern UniValue removeprunedfunds(const JSONRPCRequest& request);
extern UniValue importmulti(const JSONRPCRequest& request);
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafeMode
- // --------------------- ------------------------ ----------------------- ----------
- { "rawtransactions", "fundrawtransaction", &fundrawtransaction, false, {"hexstring","options"} },
- { "hidden", "resendwallettransactions", &resendwallettransactions, true, {} },
- { "wallet", "abandontransaction", &abandontransaction, false, {"txid"} },
- { "wallet", "addmultisigaddress", &addmultisigaddress, true, {"nrequired","keys","account"} },
- { "wallet", "addwitnessaddress", &addwitnessaddress, true, {"address"} },
- { "wallet", "backupwallet", &backupwallet, true, {"destination"} },
- { "wallet", "dumpprivkey", &dumpprivkey, true, {"address"} },
- { "wallet", "dumpwallet", &dumpwallet, true, {"filename"} },
- { "wallet", "encryptwallet", &encryptwallet, true, {"passphrase"} },
- { "wallet", "getaccountaddress", &getaccountaddress, true, {"account"} },
- { "wallet", "getaccount", &getaccount, true, {"address"} },
- { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true, {"account"} },
- { "wallet", "getbalance", &getbalance, false, {"account","minconf","include_watchonly"} },
- { "wallet", "getnewaddress", &getnewaddress, true, {"account"} },
- { "wallet", "getrawchangeaddress", &getrawchangeaddress, true, {} },
- { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, false, {"account","minconf"} },
- { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, false, {"address","minconf"} },
- { "wallet", "gettransaction", &gettransaction, false, {"txid","include_watchonly"} },
- { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, false, {} },
- { "wallet", "getwalletinfo", &getwalletinfo, false, {} },
- { "wallet", "importmulti", &importmulti, true, {"requests","options"} },
- { "wallet", "importprivkey", &importprivkey, true, {"privkey","label","rescan"} },
- { "wallet", "importwallet", &importwallet, true, {"filename"} },
- { "wallet", "importaddress", &importaddress, true, {"address","label","rescan","p2sh"} },
- { "wallet", "importprunedfunds", &importprunedfunds, true, {"rawtransaction","txoutproof"} },
- { "wallet", "importpubkey", &importpubkey, true, {"pubkey","label","rescan"} },
- { "wallet", "keypoolrefill", &keypoolrefill, true, {"newsize"} },
- { "wallet", "listaccounts", &listaccounts, false, {"minconf","include_watchonly"} },
- { "wallet", "listaddressgroupings", &listaddressgroupings, false, {} },
- { "wallet", "listlockunspent", &listlockunspent, false, {} },
- { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, false, {"minconf","include_empty","include_watchonly"} },
- { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false, {"minconf","include_empty","include_watchonly"} },
- { "wallet", "listsinceblock", &listsinceblock, false, {"blockhash","target_confirmations","include_watchonly"} },
- { "wallet", "listtransactions", &listtransactions, false, {"account","count","skip","include_watchonly"} },
- { "wallet", "listunspent", &listunspent, false, {"minconf","maxconf","addresses"} },
- { "wallet", "lockunspent", &lockunspent, true, {"unlock","transactions"} },
- { "wallet", "move", &movecmd, false, {"fromaccount","toaccount","amount","minconf","comment"} },
- { "wallet", "sendfrom", &sendfrom, false, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} },
- { "wallet", "sendmany", &sendmany, false, {"fromaccount","amounts","minconf","comment","subtractfeefrom"} },
- { "wallet", "sendtoaddress", &sendtoaddress, false, {"address","amount","comment","comment_to","subtractfeefromamount"} },
- { "wallet", "setaccount", &setaccount, true, {"address","account"} },
- { "wallet", "settxfee", &settxfee, true, {"amount"} },
- { "wallet", "signmessage", &signmessage, true, {"address","message"} },
- { "wallet", "walletlock", &walletlock, true, {} },
- { "wallet", "walletpassphrasechange", &walletpassphrasechange, true, {"oldpassphrase","newpassphrase"} },
- { "wallet", "walletpassphrase", &walletpassphrase, true, {"passphrase","timeout"} },
- { "wallet", "removeprunedfunds", &removeprunedfunds, true, {"txid"} },
+{ // category name actor (function) argNames
+ // --------------------- ------------------------ ----------------------- ----------
+ { "rawtransactions", "fundrawtransaction", &fundrawtransaction, {"hexstring","options"} },
+ { "hidden", "resendwallettransactions", &resendwallettransactions, {} },
+ { "wallet", "abandontransaction", &abandontransaction, {"txid"} },
+ { "wallet", "abortrescan", &abortrescan, {} },
+ { "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","account"} },
+ { "wallet", "addwitnessaddress", &addwitnessaddress, {"address","p2sh"} },
+ { "wallet", "backupwallet", &backupwallet, {"destination"} },
+ { "wallet", "bumpfee", &bumpfee, {"txid", "options"} },
+ { "wallet", "dumpprivkey", &dumpprivkey, {"address"} },
+ { "wallet", "dumpwallet", &dumpwallet, {"filename"} },
+ { "wallet", "encryptwallet", &encryptwallet, {"passphrase"} },
+ { "wallet", "getaccountaddress", &getaccountaddress, {"account"} },
+ { "wallet", "getaccount", &getaccount, {"address"} },
+ { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, {"account"} },
+ { "wallet", "getbalance", &getbalance, {"account","minconf","include_watchonly"} },
+ { "wallet", "getnewaddress", &getnewaddress, {"account"} },
+ { "wallet", "getrawchangeaddress", &getrawchangeaddress, {} },
+ { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, {"account","minconf"} },
+ { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, {"address","minconf"} },
+ { "wallet", "gettransaction", &gettransaction, {"txid","include_watchonly"} },
+ { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, {} },
+ { "wallet", "getwalletinfo", &getwalletinfo, {} },
+ { "wallet", "importmulti", &importmulti, {"requests","options"} },
+ { "wallet", "importprivkey", &importprivkey, {"privkey","label","rescan"} },
+ { "wallet", "importwallet", &importwallet, {"filename"} },
+ { "wallet", "importaddress", &importaddress, {"address","label","rescan","p2sh"} },
+ { "wallet", "importprunedfunds", &importprunedfunds, {"rawtransaction","txoutproof"} },
+ { "wallet", "importpubkey", &importpubkey, {"pubkey","label","rescan"} },
+ { "wallet", "keypoolrefill", &keypoolrefill, {"newsize"} },
+ { "wallet", "listaccounts", &listaccounts, {"minconf","include_watchonly"} },
+ { "wallet", "listaddressgroupings", &listaddressgroupings, {} },
+ { "wallet", "listlockunspent", &listlockunspent, {} },
+ { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, {"minconf","include_empty","include_watchonly"} },
+ { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, {"minconf","include_empty","include_watchonly"} },
+ { "wallet", "listsinceblock", &listsinceblock, {"blockhash","target_confirmations","include_watchonly","include_removed"} },
+ { "wallet", "listtransactions", &listtransactions, {"account","count","skip","include_watchonly"} },
+ { "wallet", "listunspent", &listunspent, {"minconf","maxconf","addresses","include_unsafe","query_options"} },
+ { "wallet", "listwallets", &listwallets, {} },
+ { "wallet", "lockunspent", &lockunspent, {"unlock","transactions"} },
+ { "wallet", "move", &movecmd, {"fromaccount","toaccount","amount","minconf","comment"} },
+ { "wallet", "sendfrom", &sendfrom, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} },
+ { "wallet", "sendmany", &sendmany, {"fromaccount","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} },
+ { "wallet", "sendtoaddress", &sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode"} },
+ { "wallet", "setaccount", &setaccount, {"address","account"} },
+ { "wallet", "settxfee", &settxfee, {"amount"} },
+ { "wallet", "signmessage", &signmessage, {"address","message"} },
+ { "wallet", "walletlock", &walletlock, {} },
+ { "wallet", "walletpassphrasechange", &walletpassphrasechange, {"oldpassphrase","newpassphrase"} },
+ { "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} },
+ { "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} },
+
+ { "generating", "generate", &generate, {"nblocks","maxtries"} },
};
void RegisterWalletRPCCommands(CRPCTable &t)
{
- if (GetBoolArg("-disablewallet", false))
- return;
-
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h
index 3a68ccf1b2..14e51610d9 100644
--- a/src/wallet/rpcwallet.h
+++ b/src/wallet/rpcwallet.h
@@ -5,8 +5,24 @@
#ifndef BITCOIN_WALLET_RPCWALLET_H
#define BITCOIN_WALLET_RPCWALLET_H
+#include <string>
+
class CRPCTable;
+class CWallet;
+class JSONRPCRequest;
void RegisterWalletRPCCommands(CRPCTable &t);
+/**
+ * Figures out what wallet, if any, to use for a JSONRPCRequest.
+ *
+ * @param[in] request JSONRPCRequest that wishes to access a wallet
+ * @return nullptr if no wallet should be used, or a pointer to the CWallet
+ */
+CWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest& request);
+
+std::string HelpRequiringPassphrase(CWallet *);
+void EnsureWalletIsUnlocked(CWallet *);
+bool EnsureWalletIsAvailable(CWallet *, bool avoidException);
+
#endif //BITCOIN_WALLET_RPCWALLET_H
diff --git a/src/wallet/test/accounting_tests.cpp b/src/wallet/test/accounting_tests.cpp
index 1fe633f2e5..330878ceb5 100644
--- a/src/wallet/test/accounting_tests.cpp
+++ b/src/wallet/test/accounting_tests.cpp
@@ -8,7 +8,6 @@
#include <stdint.h>
-#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
extern CWallet* pwalletMain;
@@ -23,7 +22,7 @@ GetResults(std::map<CAmount, CAccountingEntry>& results)
results.clear();
BOOST_CHECK(pwalletMain->ReorderTransactions() == DB_LOAD_OK);
pwalletMain->ListAccountCreditDebit("", aes);
- BOOST_FOREACH(CAccountingEntry& ae, aes)
+ for (CAccountingEntry& ae : aes)
{
results[ae.nOrderPos] = ae;
}
diff --git a/src/wallet/test/crypto_tests.cpp b/src/wallet/test/crypto_tests.cpp
index 0d012dacad..f4dabc50c0 100644
--- a/src/wallet/test/crypto_tests.cpp
+++ b/src/wallet/test/crypto_tests.cpp
@@ -2,94 +2,16 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "test/test_random.h"
-#include "utilstrencodings.h"
#include "test/test_bitcoin.h"
+#include "utilstrencodings.h"
#include "wallet/crypter.h"
#include <vector>
#include <boost/test/unit_test.hpp>
-#include <openssl/aes.h>
-#include <openssl/evp.h>
BOOST_FIXTURE_TEST_SUITE(wallet_crypto, BasicTestingSetup)
-bool OldSetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod, unsigned char* chKey, unsigned char* chIV)
-{
- if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
- return false;
-
- int i = 0;
- if (nDerivationMethod == 0)
- i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0],
- (unsigned char *)&strKeyData[0], strKeyData.size(), nRounds, chKey, chIV);
-
- if (i != (int)WALLET_CRYPTO_KEY_SIZE)
- {
- memory_cleanse(chKey, sizeof(chKey));
- memory_cleanse(chIV, sizeof(chIV));
- return false;
- }
- return true;
-}
-
-bool OldEncrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext, const unsigned char chKey[32], const unsigned char chIV[16])
-{
- // max ciphertext len for a n bytes of plaintext is
- // n + AES_BLOCK_SIZE - 1 bytes
- int nLen = vchPlaintext.size();
- int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0;
- vchCiphertext = std::vector<unsigned char> (nCLen);
-
- EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
-
- if (!ctx) return false;
-
- bool fOk = true;
-
- EVP_CIPHER_CTX_init(ctx);
- if (fOk) fOk = EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
- if (fOk) fOk = EVP_EncryptUpdate(ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen) != 0;
- if (fOk) fOk = EVP_EncryptFinal_ex(ctx, (&vchCiphertext[0]) + nCLen, &nFLen) != 0;
- EVP_CIPHER_CTX_cleanup(ctx);
-
- EVP_CIPHER_CTX_free(ctx);
-
- if (!fOk) return false;
-
- vchCiphertext.resize(nCLen + nFLen);
- return true;
-}
-
-bool OldDecrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext, const unsigned char chKey[32], const unsigned char chIV[16])
-{
- // plaintext will always be equal to or lesser than length of ciphertext
- int nLen = vchCiphertext.size();
- int nPLen = nLen, nFLen = 0;
-
- vchPlaintext = CKeyingMaterial(nPLen);
-
- EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
-
- if (!ctx) return false;
-
- bool fOk = true;
-
- EVP_CIPHER_CTX_init(ctx);
- if (fOk) fOk = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
- if (fOk) fOk = EVP_DecryptUpdate(ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen) != 0;
- if (fOk) fOk = EVP_DecryptFinal_ex(ctx, (&vchPlaintext[0]) + nPLen, &nFLen) != 0;
- EVP_CIPHER_CTX_cleanup(ctx);
-
- EVP_CIPHER_CTX_free(ctx);
-
- if (!fOk) return false;
-
- vchPlaintext.resize(nPLen + nFLen);
- return true;
-}
-
class TestCrypter
{
public:
@@ -97,25 +19,15 @@ static void TestPassphraseSingle(const std::vector<unsigned char>& vchSalt, cons
const std::vector<unsigned char>& correctKey = std::vector<unsigned char>(),
const std::vector<unsigned char>& correctIV=std::vector<unsigned char>())
{
- unsigned char chKey[WALLET_CRYPTO_KEY_SIZE];
- unsigned char chIV[WALLET_CRYPTO_IV_SIZE];
-
CCrypter crypt;
crypt.SetKeyFromPassphrase(passphrase, vchSalt, rounds, 0);
- OldSetKeyFromPassphrase(passphrase, vchSalt, rounds, 0, chKey, chIV);
-
- BOOST_CHECK_MESSAGE(memcmp(chKey, crypt.vchKey.data(), crypt.vchKey.size()) == 0, \
- HexStr(chKey, chKey+sizeof(chKey)) + std::string(" != ") + HexStr(crypt.vchKey));
- BOOST_CHECK_MESSAGE(memcmp(chIV, crypt.vchIV.data(), crypt.vchIV.size()) == 0, \
- HexStr(chIV, chIV+sizeof(chIV)) + std::string(" != ") + HexStr(crypt.vchIV));
-
if(!correctKey.empty())
- BOOST_CHECK_MESSAGE(memcmp(chKey, &correctKey[0], sizeof(chKey)) == 0, \
- HexStr(chKey, chKey+sizeof(chKey)) + std::string(" != ") + HexStr(correctKey.begin(), correctKey.end()));
+ BOOST_CHECK_MESSAGE(memcmp(crypt.vchKey.data(), correctKey.data(), crypt.vchKey.size()) == 0, \
+ HexStr(crypt.vchKey.begin(), crypt.vchKey.end()) + std::string(" != ") + HexStr(correctKey.begin(), correctKey.end()));
if(!correctIV.empty())
- BOOST_CHECK_MESSAGE(memcmp(chIV, &correctIV[0], sizeof(chIV)) == 0,
- HexStr(chIV, chIV+sizeof(chIV)) + std::string(" != ") + HexStr(correctIV.begin(), correctIV.end()));
+ BOOST_CHECK_MESSAGE(memcmp(crypt.vchIV.data(), correctIV.data(), crypt.vchIV.size()) == 0,
+ HexStr(crypt.vchIV.begin(), crypt.vchIV.end()) + std::string(" != ") + HexStr(correctIV.begin(), correctIV.end()));
}
static void TestPassphrase(const std::vector<unsigned char>& vchSalt, const SecureString& passphrase, uint32_t rounds,
@@ -127,50 +39,26 @@ static void TestPassphrase(const std::vector<unsigned char>& vchSalt, const Secu
TestPassphraseSingle(vchSalt, SecureString(i, passphrase.end()), rounds);
}
-
static void TestDecrypt(const CCrypter& crypt, const std::vector<unsigned char>& vchCiphertext, \
const std::vector<unsigned char>& vchPlaintext = std::vector<unsigned char>())
{
- CKeyingMaterial vchDecrypted1;
- CKeyingMaterial vchDecrypted2;
- int result1, result2;
- result1 = crypt.Decrypt(vchCiphertext, vchDecrypted1);
- result2 = OldDecrypt(vchCiphertext, vchDecrypted2, crypt.vchKey.data(), crypt.vchIV.data());
- BOOST_CHECK(result1 == result2);
-
- // These two should be equal. However, OpenSSL 1.0.1j introduced a change
- // that would zero all padding except for the last byte for failed decrypts.
- // This behavior was reverted for 1.0.1k.
- if (vchDecrypted1 != vchDecrypted2 && vchDecrypted1.size() >= AES_BLOCK_SIZE && SSLeay() == 0x100010afL)
- {
- for(CKeyingMaterial::iterator it = vchDecrypted1.end() - AES_BLOCK_SIZE; it != vchDecrypted1.end() - 1; it++)
- *it = 0;
- }
-
- BOOST_CHECK_MESSAGE(vchDecrypted1 == vchDecrypted2, HexStr(vchDecrypted1.begin(), vchDecrypted1.end()) + " != " + HexStr(vchDecrypted2.begin(), vchDecrypted2.end()));
-
+ CKeyingMaterial vchDecrypted;
+ crypt.Decrypt(vchCiphertext, vchDecrypted);
if (vchPlaintext.size())
- BOOST_CHECK(CKeyingMaterial(vchPlaintext.begin(), vchPlaintext.end()) == vchDecrypted2);
+ BOOST_CHECK(CKeyingMaterial(vchPlaintext.begin(), vchPlaintext.end()) == vchDecrypted);
}
static void TestEncryptSingle(const CCrypter& crypt, const CKeyingMaterial& vchPlaintext,
const std::vector<unsigned char>& vchCiphertextCorrect = std::vector<unsigned char>())
{
- std::vector<unsigned char> vchCiphertext1;
- std::vector<unsigned char> vchCiphertext2;
- int result1 = crypt.Encrypt(vchPlaintext, vchCiphertext1);
-
- int result2 = OldEncrypt(vchPlaintext, vchCiphertext2, crypt.vchKey.data(), crypt.vchIV.data());
- BOOST_CHECK(result1 == result2);
- BOOST_CHECK(vchCiphertext1 == vchCiphertext2);
+ std::vector<unsigned char> vchCiphertext;
+ crypt.Encrypt(vchPlaintext, vchCiphertext);
if (!vchCiphertextCorrect.empty())
- BOOST_CHECK(vchCiphertext2 == vchCiphertextCorrect);
+ BOOST_CHECK(vchCiphertext == vchCiphertextCorrect);
const std::vector<unsigned char> vchPlaintext2(vchPlaintext.begin(), vchPlaintext.end());
-
- if(vchCiphertext1 == vchCiphertext2)
- TestDecrypt(crypt, vchCiphertext1, vchPlaintext2);
+ TestDecrypt(crypt, vchCiphertext, vchPlaintext2);
}
static void TestEncrypt(const CCrypter& crypt, const std::vector<unsigned char>& vchPlaintextIn, \
@@ -192,8 +80,8 @@ BOOST_AUTO_TEST_CASE(passphrase) {
std::string hash(GetRandHash().ToString());
std::vector<unsigned char> vchSalt(8);
- GetRandBytes(&vchSalt[0], vchSalt.size());
- uint32_t rounds = insecure_rand();
+ GetRandBytes(vchSalt.data(), vchSalt.size());
+ uint32_t rounds = InsecureRand32();
if (rounds > 30000)
rounds = 30000;
TestCrypter::TestPassphrase(vchSalt, SecureString(hash.begin(), hash.end()), rounds);
diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp
index a76db37617..e2f48c45ab 100644
--- a/src/wallet/test/wallet_test_fixture.cpp
+++ b/src/wallet/test/wallet_test_fixture.cpp
@@ -8,13 +8,16 @@
#include "wallet/db.h"
#include "wallet/wallet.h"
+CWallet *pwalletMain;
+
WalletTestingSetup::WalletTestingSetup(const std::string& chainName):
TestingSetup(chainName)
{
bitdb.MakeMock();
bool fFirstRun;
- pwalletMain = new CWallet("wallet_test.dat");
+ std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, "wallet_test.dat"));
+ pwalletMain = new CWallet(std::move(dbw));
pwalletMain->LoadWallet(fFirstRun);
RegisterValidationInterface(pwalletMain);
@@ -25,7 +28,7 @@ WalletTestingSetup::~WalletTestingSetup()
{
UnregisterValidationInterface(pwalletMain);
delete pwalletMain;
- pwalletMain = NULL;
+ pwalletMain = nullptr;
bitdb.Flush(true);
bitdb.Reset();
diff --git a/src/wallet/test/wallet_test_fixture.h b/src/wallet/test/wallet_test_fixture.h
index 97a6d98397..9373b7907c 100644
--- a/src/wallet/test/wallet_test_fixture.h
+++ b/src/wallet/test/wallet_test_fixture.h
@@ -10,7 +10,7 @@
/** Testing setup and teardown for wallet.
*/
struct WalletTestingSetup: public TestingSetup {
- WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
+ explicit WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
~WalletTestingSetup();
};
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index c7ce6fd243..5ebacd57d3 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -9,10 +9,21 @@
#include <utility>
#include <vector>
+#include "consensus/validation.h"
+#include "rpc/server.h"
+#include "test/test_bitcoin.h"
+#include "validation.h"
+#include "wallet/coincontrol.h"
#include "wallet/test/wallet_test_fixture.h"
-#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
+#include <univalue.h>
+
+extern CWallet* pwalletMain;
+
+extern UniValue importmulti(const JSONRPCRequest& request);
+extern UniValue dumpwallet(const JSONRPCRequest& request);
+extern UniValue importwallet(const JSONRPCRequest& request);
// how many times to run all the tests to have a chance to catch errors that only show up with particular random shuffles
#define RUN_TESTS 100
@@ -21,14 +32,14 @@
// we repeat those tests this many times and only complain if all iterations of the test fail
#define RANDOM_REPEATS 5
-using namespace std;
+std::vector<std::unique_ptr<CWalletTx>> wtxn;
-typedef set<pair<const CWalletTx*,unsigned int> > CoinSet;
+typedef std::set<CInputCoin> CoinSet;
BOOST_FIXTURE_TEST_SUITE(wallet_tests, WalletTestingSetup)
-static const CWallet wallet;
-static vector<COutput> vCoins;
+static const CWallet testWallet;
+static std::vector<COutput> vCoins;
static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0)
{
@@ -42,26 +53,26 @@ static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = fa
// so stop vin being empty, and cache a non-zero Debit to fake out IsFromMe()
tx.vin.resize(1);
}
- CWalletTx* wtx = new CWalletTx(&wallet, MakeTransactionRef(std::move(tx)));
+ std::unique_ptr<CWalletTx> wtx(new CWalletTx(&testWallet, MakeTransactionRef(std::move(tx))));
if (fIsFromMe)
{
wtx->fDebitCached = true;
wtx->nDebitCached = 1;
}
- COutput output(wtx, nInput, nAge, true, true);
+ COutput output(wtx.get(), nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
vCoins.push_back(output);
+ wtxn.emplace_back(std::move(wtx));
}
static void empty_wallet(void)
{
- BOOST_FOREACH(COutput output, vCoins)
- delete output.tx;
vCoins.clear();
+ wtxn.clear();
}
static bool equal_sets(CoinSet a, CoinSet b)
{
- pair<CoinSet::iterator, CoinSet::iterator> ret = mismatch(a.begin(), a.end(), b.begin());
+ std::pair<CoinSet::iterator, CoinSet::iterator> ret = mismatch(a.begin(), a.end(), b.begin());
return ret.first == a.end() && ret.second == b.end();
}
@@ -70,7 +81,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
CoinSet setCoinsRet, setCoinsRet2;
CAmount nValueRet;
- LOCK(wallet.cs_wallet);
+ LOCK(testWallet.cs_wallet);
// test multiple times to allow for differences in the shuffle order
for (int i = 0; i < RUN_TESTS; i++)
@@ -78,24 +89,24 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
empty_wallet();
// with an empty wallet we can't even pay one cent
- BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK(!testWallet.SelectCoinsMinConf( 1 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet));
add_coin(1*CENT, 4); // add a new 1 cent coin
// with a new 1 cent coin, we still can't find a mature 1 cent
- BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK(!testWallet.SelectCoinsMinConf( 1 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet));
// but we can find a new 1 cent
- BOOST_CHECK( wallet.SelectCoinsMinConf( 1 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( testWallet.SelectCoinsMinConf( 1 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 1 * CENT);
add_coin(2*CENT); // add a mature 2 cent coin
// we can't make 3 cents of mature coins
- BOOST_CHECK(!wallet.SelectCoinsMinConf( 3 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK(!testWallet.SelectCoinsMinConf( 3 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet));
// we can make 3 cents of new coins
- BOOST_CHECK( wallet.SelectCoinsMinConf( 3 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( testWallet.SelectCoinsMinConf( 3 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 3 * CENT);
add_coin(5*CENT); // add a mature 5 cent coin,
@@ -105,33 +116,33 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
// now we have new: 1+10=11 (of which 10 was self-sent), and mature: 2+5+20=27. total = 38
// we can't make 38 cents only if we disallow new coins:
- BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK(!testWallet.SelectCoinsMinConf(38 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet));
// we can't even make 37 cents if we don't allow new coins even if they're from us
- BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 6, 6, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK(!testWallet.SelectCoinsMinConf(38 * CENT, 6, 6, 0, vCoins, setCoinsRet, nValueRet));
// but we can make 37 cents if we accept new coins from ourself
- BOOST_CHECK( wallet.SelectCoinsMinConf(37 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( testWallet.SelectCoinsMinConf(37 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 37 * CENT);
// and we can make 38 cents if we accept all new coins
- BOOST_CHECK( wallet.SelectCoinsMinConf(38 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( testWallet.SelectCoinsMinConf(38 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 38 * CENT);
// try making 34 cents from 1,2,5,10,20 - we can't do it exactly
- BOOST_CHECK( wallet.SelectCoinsMinConf(34 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( testWallet.SelectCoinsMinConf(34 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 35 * CENT); // but 35 cents is closest
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); // the best should be 20+10+5. it's incredibly unlikely the 1 or 2 got included (but possible)
// when we try making 7 cents, the smaller coins (1,2,5) are enough. We should see just 2+5
- BOOST_CHECK( wallet.SelectCoinsMinConf( 7 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( testWallet.SelectCoinsMinConf( 7 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 7 * CENT);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
// when we try making 8 cents, the smaller coins (1,2,5) are exactly enough.
- BOOST_CHECK( wallet.SelectCoinsMinConf( 8 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( testWallet.SelectCoinsMinConf( 8 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK(nValueRet == 8 * CENT);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);
// when we try making 9 cents, no subset of smaller coins is enough, and we get the next bigger coin (10)
- BOOST_CHECK( wallet.SelectCoinsMinConf( 9 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( testWallet.SelectCoinsMinConf( 9 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 10 * CENT);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
@@ -145,30 +156,30 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
add_coin(30*CENT); // now we have 6+7+8+20+30 = 71 cents total
// check that we have 71 and not 72
- BOOST_CHECK( wallet.SelectCoinsMinConf(71 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
- BOOST_CHECK(!wallet.SelectCoinsMinConf(72 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( testWallet.SelectCoinsMinConf(71 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK(!testWallet.SelectCoinsMinConf(72 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
// now try making 16 cents. the best smaller coins can do is 6+7+8 = 21; not as good at the next biggest coin, 20
- BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( testWallet.SelectCoinsMinConf(16 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 20 * CENT); // we should get 20 in one coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
add_coin( 5*CENT); // now we have 5+6+7+8+20+30 = 75 cents total
// now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, better than the next biggest coin, 20
- BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( testWallet.SelectCoinsMinConf(16 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 3 coins
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);
add_coin( 18*CENT); // now we have 5+6+7+8+18+20+30
// and now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, the same as the next biggest coin, 18
- BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( testWallet.SelectCoinsMinConf(16 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 1 coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); // because in the event of a tie, the biggest coin wins
// now try making 11 cents. we should get 5+6
- BOOST_CHECK( wallet.SelectCoinsMinConf(11 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( testWallet.SelectCoinsMinConf(11 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 11 * CENT);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
@@ -177,11 +188,11 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
add_coin( 2*COIN);
add_coin( 3*COIN);
add_coin( 4*COIN); // now we have 5+6+7+8+18+20+30+100+200+300+400 = 1094 cents
- BOOST_CHECK( wallet.SelectCoinsMinConf(95 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( testWallet.SelectCoinsMinConf(95 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 1 * COIN); // we should get 1 BTC in 1 coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
- BOOST_CHECK( wallet.SelectCoinsMinConf(195 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( testWallet.SelectCoinsMinConf(195 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 2 * COIN); // we should get 2 BTC in 1 coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
@@ -196,14 +207,14 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
// try making 1 * MIN_CHANGE from the 1.5 * MIN_CHANGE
// we'll get change smaller than MIN_CHANGE whatever happens, so can expect MIN_CHANGE exactly
- BOOST_CHECK( wallet.SelectCoinsMinConf(MIN_CHANGE, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( testWallet.SelectCoinsMinConf(MIN_CHANGE, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE);
// but if we add a bigger coin, small change is avoided
add_coin(1111*MIN_CHANGE);
// try making 1 from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 + 1111 = 1112.5
- BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( testWallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); // we should get the exact amount
// if we add more small coins:
@@ -211,7 +222,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
add_coin(MIN_CHANGE * 7 / 10);
// and try again to make 1.0 * MIN_CHANGE
- BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( testWallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); // we should get the exact amount
// run the 'mtgox' test (see http://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf)
@@ -220,7 +231,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
for (int j = 0; j < 20; j++)
add_coin(50000 * COIN);
- BOOST_CHECK( wallet.SelectCoinsMinConf(500000 * COIN, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( testWallet.SelectCoinsMinConf(500000 * COIN, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 500000 * COIN); // we should get the exact amount
BOOST_CHECK_EQUAL(setCoinsRet.size(), 10U); // in ten coins
@@ -233,7 +244,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
add_coin(MIN_CHANGE * 6 / 10);
add_coin(MIN_CHANGE * 7 / 10);
add_coin(1111 * MIN_CHANGE);
- BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( testWallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 1111 * MIN_CHANGE); // we get the bigger coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
@@ -243,7 +254,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
add_coin(MIN_CHANGE * 6 / 10);
add_coin(MIN_CHANGE * 8 / 10);
add_coin(1111 * MIN_CHANGE);
- BOOST_CHECK( wallet.SelectCoinsMinConf(MIN_CHANGE, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( testWallet.SelectCoinsMinConf(MIN_CHANGE, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE); // we should get the exact amount
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); // in two coins 0.4+0.6
@@ -254,12 +265,12 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
add_coin(MIN_CHANGE * 100);
// trying to make 100.01 from these three coins
- BOOST_CHECK(wallet.SelectCoinsMinConf(MIN_CHANGE * 10001 / 100, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK(testWallet.SelectCoinsMinConf(MIN_CHANGE * 10001 / 100, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE * 10105 / 100); // we should get all coins
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);
// but if we try to make 99.9, we should take the bigger of the two small coins to avoid small change
- BOOST_CHECK(wallet.SelectCoinsMinConf(MIN_CHANGE * 9990 / 100, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK(testWallet.SelectCoinsMinConf(MIN_CHANGE * 9990 / 100, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 101 * MIN_CHANGE);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
@@ -269,7 +280,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
// Create 676 inputs (= (old MAX_STANDARD_TX_SIZE == 100000) / 148 bytes per input)
for (uint16_t j = 0; j < 676; j++)
add_coin(amt);
- BOOST_CHECK(wallet.SelectCoinsMinConf(2000, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK(testWallet.SelectCoinsMinConf(2000, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
if (amt - 2000 < MIN_CHANGE) {
// needs more than one input:
uint16_t returnSize = std::ceil((2000.0 + MIN_CHANGE)/amt);
@@ -291,8 +302,8 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
// picking 50 from 100 coins doesn't depend on the shuffle,
// but does depend on randomness in the stochastic approximation code
- BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, 0, vCoins, setCoinsRet , nValueRet));
- BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, 0, vCoins, setCoinsRet2, nValueRet));
+ BOOST_CHECK(testWallet.SelectCoinsMinConf(50 * COIN, 1, 6, 0, vCoins, setCoinsRet , nValueRet));
+ BOOST_CHECK(testWallet.SelectCoinsMinConf(50 * COIN, 1, 6, 0, vCoins, setCoinsRet2, nValueRet));
BOOST_CHECK(!equal_sets(setCoinsRet, setCoinsRet2));
int fails = 0;
@@ -300,8 +311,8 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
{
// selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time
// run the test RANDOM_REPEATS times and only complain if all of them fail
- BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, 0, vCoins, setCoinsRet , nValueRet));
- BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, 0, vCoins, setCoinsRet2, nValueRet));
+ BOOST_CHECK(testWallet.SelectCoinsMinConf(COIN, 1, 6, 0, vCoins, setCoinsRet , nValueRet));
+ BOOST_CHECK(testWallet.SelectCoinsMinConf(COIN, 1, 6, 0, vCoins, setCoinsRet2, nValueRet));
if (equal_sets(setCoinsRet, setCoinsRet2))
fails++;
}
@@ -321,8 +332,8 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
{
// selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time
// run the test RANDOM_REPEATS times and only complain if all of them fail
- BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, 1, 6, 0, vCoins, setCoinsRet , nValueRet));
- BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, 1, 6, 0, vCoins, setCoinsRet2, nValueRet));
+ BOOST_CHECK(testWallet.SelectCoinsMinConf(90*CENT, 1, 6, 0, vCoins, setCoinsRet , nValueRet));
+ BOOST_CHECK(testWallet.SelectCoinsMinConf(90*CENT, 1, 6, 0, vCoins, setCoinsRet2, nValueRet));
if (equal_sets(setCoinsRet, setCoinsRet2))
fails++;
}
@@ -337,7 +348,7 @@ BOOST_AUTO_TEST_CASE(ApproximateBestSubset)
CoinSet setCoinsRet;
CAmount nValueRet;
- LOCK(wallet.cs_wallet);
+ LOCK(testWallet.cs_wallet);
empty_wallet();
@@ -346,9 +357,327 @@ BOOST_AUTO_TEST_CASE(ApproximateBestSubset)
add_coin(1000 * COIN);
add_coin(3 * COIN);
- BOOST_CHECK(wallet.SelectCoinsMinConf(1003 * COIN, 1, 6, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK(testWallet.SelectCoinsMinConf(1003 * COIN, 1, 6, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 1003 * COIN);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
+
+ empty_wallet();
+}
+
+static void AddKey(CWallet& wallet, const CKey& key)
+{
+ LOCK(wallet.cs_wallet);
+ wallet.AddKeyPubKey(key, key.GetPubKey());
+}
+
+BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
+{
+ LOCK(cs_main);
+
+ // Cap last block file size, and mine new block in a new block file.
+ CBlockIndex* const nullBlock = nullptr;
+ CBlockIndex* oldTip = chainActive.Tip();
+ GetBlockFileInfo(oldTip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE;
+ CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
+ CBlockIndex* newTip = chainActive.Tip();
+
+ // Verify ScanForWalletTransactions picks up transactions in both the old
+ // and new block files.
+ {
+ CWallet wallet;
+ AddKey(wallet, coinbaseKey);
+ BOOST_CHECK_EQUAL(nullBlock, wallet.ScanForWalletTransactions(oldTip));
+ BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 100 * COIN);
+ }
+
+ // Prune the older block file.
+ PruneOneBlockFile(oldTip->GetBlockPos().nFile);
+ UnlinkPrunedFiles({oldTip->GetBlockPos().nFile});
+
+ // Verify ScanForWalletTransactions only picks transactions in the new block
+ // file.
+ {
+ CWallet wallet;
+ AddKey(wallet, coinbaseKey);
+ BOOST_CHECK_EQUAL(oldTip, wallet.ScanForWalletTransactions(oldTip));
+ BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 50 * COIN);
+ }
+
+ // Verify importmulti RPC returns failure for a key whose creation time is
+ // before the missing block, and success for a key whose creation time is
+ // after.
+ {
+ CWallet wallet;
+ vpwallets.insert(vpwallets.begin(), &wallet);
+ UniValue keys;
+ keys.setArray();
+ UniValue key;
+ key.setObject();
+ key.pushKV("scriptPubKey", HexStr(GetScriptForRawPubKey(coinbaseKey.GetPubKey())));
+ key.pushKV("timestamp", 0);
+ key.pushKV("internal", UniValue(true));
+ keys.push_back(key);
+ key.clear();
+ key.setObject();
+ CKey futureKey;
+ futureKey.MakeNewKey(true);
+ key.pushKV("scriptPubKey", HexStr(GetScriptForRawPubKey(futureKey.GetPubKey())));
+ key.pushKV("timestamp", newTip->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1);
+ key.pushKV("internal", UniValue(true));
+ keys.push_back(key);
+ JSONRPCRequest request;
+ request.params.setArray();
+ request.params.push_back(keys);
+
+ UniValue response = importmulti(request);
+ BOOST_CHECK_EQUAL(response.write(),
+ strprintf("[{\"success\":false,\"error\":{\"code\":-1,\"message\":\"Rescan failed for key with creation "
+ "timestamp %d. There was an error reading a block from time %d, which is after or within %d "
+ "seconds of key creation, and could contain transactions pertaining to the key. As a result, "
+ "transactions and coins using this key may not appear in the wallet. This error could be caused "
+ "by pruning or data corruption (see bitcoind log for details) and could be dealt with by "
+ "downloading and rescanning the relevant blocks (see -reindex and -rescan "
+ "options).\"}},{\"success\":true}]",
+ 0, oldTip->GetBlockTimeMax(), TIMESTAMP_WINDOW));
+ vpwallets.erase(vpwallets.begin());
+ }
+}
+
+// Verify importwallet RPC starts rescan at earliest block with timestamp
+// greater or equal than key birthday. Previously there was a bug where
+// importwallet RPC would start the scan at the latest block with timestamp less
+// than or equal to key birthday.
+BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
+{
+ LOCK(cs_main);
+
+ // Create two blocks with same timestamp to verify that importwallet rescan
+ // will pick up both blocks, not just the first.
+ const int64_t BLOCK_TIME = chainActive.Tip()->GetBlockTimeMax() + 5;
+ SetMockTime(BLOCK_TIME);
+ coinbaseTxns.emplace_back(*CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
+ coinbaseTxns.emplace_back(*CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
+
+ // Set key birthday to block time increased by the timestamp window, so
+ // rescan will start at the block time.
+ const int64_t KEY_TIME = BLOCK_TIME + TIMESTAMP_WINDOW;
+ SetMockTime(KEY_TIME);
+ coinbaseTxns.emplace_back(*CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
+
+ // Import key into wallet and call dumpwallet to create backup file.
+ {
+ CWallet wallet;
+ LOCK(wallet.cs_wallet);
+ wallet.mapKeyMetadata[coinbaseKey.GetPubKey().GetID()].nCreateTime = KEY_TIME;
+ wallet.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
+
+ JSONRPCRequest request;
+ request.params.setArray();
+ request.params.push_back((pathTemp / "wallet.backup").string());
+ vpwallets.insert(vpwallets.begin(), &wallet);
+ ::dumpwallet(request);
+ }
+
+ // Call importwallet RPC and verify all blocks with timestamps >= BLOCK_TIME
+ // were scanned, and no prior blocks were scanned.
+ {
+ CWallet wallet;
+
+ JSONRPCRequest request;
+ request.params.setArray();
+ request.params.push_back((pathTemp / "wallet.backup").string());
+ vpwallets[0] = &wallet;
+ ::importwallet(request);
+
+ BOOST_CHECK_EQUAL(wallet.mapWallet.size(), 3);
+ BOOST_CHECK_EQUAL(coinbaseTxns.size(), 103);
+ for (size_t i = 0; i < coinbaseTxns.size(); ++i) {
+ bool found = wallet.GetWalletTx(coinbaseTxns[i].GetHash());
+ bool expected = i >= 100;
+ BOOST_CHECK_EQUAL(found, expected);
+ }
+ }
+
+ SetMockTime(0);
+ vpwallets.erase(vpwallets.begin());
+}
+
+// Check that GetImmatureCredit() returns a newly calculated value instead of
+// the cached value after a MarkDirty() call.
+//
+// This is a regression test written to verify a bugfix for the immature credit
+// function. Similar tests probably should be written for the other credit and
+// debit functions.
+BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
+{
+ CWallet wallet;
+ CWalletTx wtx(&wallet, MakeTransactionRef(coinbaseTxns.back()));
+ LOCK2(cs_main, wallet.cs_wallet);
+ wtx.hashBlock = chainActive.Tip()->GetBlockHash();
+ wtx.nIndex = 0;
+
+ // Call GetImmatureCredit() once before adding the key to the wallet to
+ // cache the current immature credit amount, which is 0.
+ BOOST_CHECK_EQUAL(wtx.GetImmatureCredit(), 0);
+
+ // Invalidate the cached value, add the key, and make sure a new immature
+ // credit amount is calculated.
+ wtx.MarkDirty();
+ wallet.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
+ BOOST_CHECK_EQUAL(wtx.GetImmatureCredit(), 50*COIN);
+}
+
+static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64_t blockTime)
+{
+ CMutableTransaction tx;
+ tx.nLockTime = lockTime;
+ SetMockTime(mockTime);
+ CBlockIndex* block = nullptr;
+ if (blockTime > 0) {
+ auto inserted = mapBlockIndex.emplace(GetRandHash(), new CBlockIndex);
+ assert(inserted.second);
+ const uint256& hash = inserted.first->first;
+ block = inserted.first->second;
+ block->nTime = blockTime;
+ block->phashBlock = &hash;
+ }
+
+ CWalletTx wtx(&wallet, MakeTransactionRef(tx));
+ if (block) {
+ wtx.SetMerkleBranch(block, 0);
+ }
+ wallet.AddToWallet(wtx);
+ return wallet.mapWallet.at(wtx.GetHash()).nTimeSmart;
+}
+
+// Simple test to verify assignment of CWalletTx::nSmartTime value. Could be
+// expanded to cover more corner cases of smart time logic.
+BOOST_AUTO_TEST_CASE(ComputeTimeSmart)
+{
+ CWallet wallet;
+
+ // New transaction should use clock time if lower than block time.
+ BOOST_CHECK_EQUAL(AddTx(wallet, 1, 100, 120), 100);
+
+ // Test that updating existing transaction does not change smart time.
+ BOOST_CHECK_EQUAL(AddTx(wallet, 1, 200, 220), 100);
+
+ // New transaction should use clock time if there's no block time.
+ BOOST_CHECK_EQUAL(AddTx(wallet, 2, 300, 0), 300);
+
+ // New transaction should use block time if lower than clock time.
+ BOOST_CHECK_EQUAL(AddTx(wallet, 3, 420, 400), 400);
+
+ // New transaction should use latest entry time if higher than
+ // min(block time, clock time).
+ BOOST_CHECK_EQUAL(AddTx(wallet, 4, 500, 390), 400);
+
+ // If there are future entries, new transaction should use time of the
+ // newest entry that is no more than 300 seconds ahead of the clock time.
+ BOOST_CHECK_EQUAL(AddTx(wallet, 5, 50, 600), 300);
+
+ // Reset mock time for other tests.
+ SetMockTime(0);
+}
+
+BOOST_AUTO_TEST_CASE(LoadReceiveRequests)
+{
+ CTxDestination dest = CKeyID();
+ pwalletMain->AddDestData(dest, "misc", "val_misc");
+ pwalletMain->AddDestData(dest, "rr0", "val_rr0");
+ pwalletMain->AddDestData(dest, "rr1", "val_rr1");
+
+ auto values = pwalletMain->GetDestValues("rr");
+ BOOST_CHECK_EQUAL(values.size(), 2);
+ BOOST_CHECK_EQUAL(values[0], "val_rr0");
+ BOOST_CHECK_EQUAL(values[1], "val_rr1");
+}
+
+class ListCoinsTestingSetup : public TestChain100Setup
+{
+public:
+ ListCoinsTestingSetup()
+ {
+ CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
+ ::bitdb.MakeMock();
+ wallet.reset(new CWallet(std::unique_ptr<CWalletDBWrapper>(new CWalletDBWrapper(&bitdb, "wallet_test.dat"))));
+ bool firstRun;
+ wallet->LoadWallet(firstRun);
+ AddKey(*wallet, coinbaseKey);
+ wallet->ScanForWalletTransactions(chainActive.Genesis());
+ }
+
+ ~ListCoinsTestingSetup()
+ {
+ wallet.reset();
+ ::bitdb.Flush(true);
+ ::bitdb.Reset();
+ }
+
+ CWalletTx& AddTx(CRecipient recipient)
+ {
+ CWalletTx wtx;
+ CReserveKey reservekey(wallet.get());
+ CAmount fee;
+ int changePos = -1;
+ std::string error;
+ CCoinControl dummy;
+ BOOST_CHECK(wallet->CreateTransaction({recipient}, wtx, reservekey, fee, changePos, error, dummy));
+ CValidationState state;
+ BOOST_CHECK(wallet->CommitTransaction(wtx, reservekey, nullptr, state));
+ auto it = wallet->mapWallet.find(wtx.GetHash());
+ BOOST_CHECK(it != wallet->mapWallet.end());
+ CreateAndProcessBlock({CMutableTransaction(*it->second.tx)}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
+ it->second.SetMerkleBranch(chainActive.Tip(), 1);
+ return it->second;
+ }
+
+ std::unique_ptr<CWallet> wallet;
+};
+
+BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
+{
+ std::string coinbaseAddress = coinbaseKey.GetPubKey().GetID().ToString();
+ LOCK2(cs_main, wallet->cs_wallet);
+
+ // Confirm ListCoins initially returns 1 coin grouped under coinbaseKey
+ // address.
+ auto list = wallet->ListCoins();
+ BOOST_CHECK_EQUAL(list.size(), 1);
+ BOOST_CHECK_EQUAL(boost::get<CKeyID>(list.begin()->first).ToString(), coinbaseAddress);
+ BOOST_CHECK_EQUAL(list.begin()->second.size(), 1);
+
+ // Check initial balance from one mature coinbase transaction.
+ BOOST_CHECK_EQUAL(50 * COIN, wallet->GetAvailableBalance());
+
+ // Add a transaction creating a change address, and confirm ListCoins still
+ // returns the coin associated with the change address underneath the
+ // coinbaseKey pubkey, even though the change address has a different
+ // pubkey.
+ AddTx(CRecipient{GetScriptForRawPubKey({}), 1 * COIN, false /* subtract fee */});
+ list = wallet->ListCoins();
+ BOOST_CHECK_EQUAL(list.size(), 1);
+ BOOST_CHECK_EQUAL(boost::get<CKeyID>(list.begin()->first).ToString(), coinbaseAddress);
+ BOOST_CHECK_EQUAL(list.begin()->second.size(), 2);
+
+ // Lock both coins. Confirm number of available coins drops to 0.
+ std::vector<COutput> available;
+ wallet->AvailableCoins(available);
+ BOOST_CHECK_EQUAL(available.size(), 2);
+ for (const auto& group : list) {
+ for (const auto& coin : group.second) {
+ wallet->LockCoin(COutPoint(coin.tx->GetHash(), coin.i));
+ }
+ }
+ wallet->AvailableCoins(available);
+ BOOST_CHECK_EQUAL(available.size(), 0);
+
+ // Confirm ListCoins still returns same result as before, despite coins
+ // being locked.
+ list = wallet->ListCoins();
+ BOOST_CHECK_EQUAL(list.size(), 1);
+ BOOST_CHECK_EQUAL(boost::get<CKeyID>(list.begin()->first).ToString(), coinbaseAddress);
+ BOOST_CHECK_EQUAL(list.begin()->second.size(), 2);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index b4ea77a8f0..925b474d73 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -11,35 +11,37 @@
#include "wallet/coincontrol.h"
#include "consensus/consensus.h"
#include "consensus/validation.h"
+#include "fs.h"
+#include "init.h"
#include "key.h"
#include "keystore.h"
#include "validation.h"
#include "net.h"
+#include "policy/fees.h"
#include "policy/policy.h"
+#include "policy/rbf.h"
#include "primitives/block.h"
#include "primitives/transaction.h"
#include "script/script.h"
#include "script/sign.h"
+#include "scheduler.h"
#include "timedata.h"
#include "txmempool.h"
#include "util.h"
#include "ui_interface.h"
#include "utilmoneystr.h"
+#include "wallet/fees.h"
#include <assert.h>
#include <boost/algorithm/string/replace.hpp>
-#include <boost/filesystem.hpp>
#include <boost/thread.hpp>
-using namespace std;
-
-CWallet* pwalletMain = NULL;
+std::vector<CWalletRef> vpwallets;
/** Transaction fee set by the user */
CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET;
bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE;
-bool fSendFreeTransactions = DEFAULT_SEND_FREE_TRANSACTIONS;
bool fWalletRbf = DEFAULT_WALLET_RBF;
const char * DEFAULT_WALLET_DAT = "wallet.dat";
@@ -57,6 +59,8 @@ CFeeRate CWallet::minTxFee = CFeeRate(DEFAULT_TRANSACTION_MINFEE);
*/
CFeeRate CWallet::fallbackFee = CFeeRate(DEFAULT_FALLBACK_FEE);
+CFeeRate CWallet::m_discard_rate = CFeeRate(DEFAULT_DISCARD_FEE);
+
const uint256 CMerkleTx::ABANDON_HASH(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
/** @defgroup mapWallet
@@ -66,10 +70,10 @@ const uint256 CMerkleTx::ABANDON_HASH(uint256S("00000000000000000000000000000000
struct CompareValueOnly
{
- bool operator()(const pair<CAmount, pair<const CWalletTx*, unsigned int> >& t1,
- const pair<CAmount, pair<const CWalletTx*, unsigned int> >& t2) const
+ bool operator()(const CInputCoin& t1,
+ const CInputCoin& t2) const
{
- return t1.first < t2.first;
+ return t1.txout.nValue < t2.txout.nValue;
}
};
@@ -78,16 +82,67 @@ std::string COutput::ToString() const
return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->tx->vout[i].nValue));
}
+class CAffectedKeysVisitor : public boost::static_visitor<void> {
+private:
+ const CKeyStore &keystore;
+ std::vector<CKeyID> &vKeys;
+
+public:
+ CAffectedKeysVisitor(const CKeyStore &keystoreIn, std::vector<CKeyID> &vKeysIn) : keystore(keystoreIn), vKeys(vKeysIn) {}
+
+ void Process(const CScript &script) {
+ txnouttype type;
+ std::vector<CTxDestination> vDest;
+ int nRequired;
+ if (ExtractDestinations(script, type, vDest, nRequired)) {
+ for (const CTxDestination &dest : vDest)
+ boost::apply_visitor(*this, dest);
+ }
+ }
+
+ void operator()(const CKeyID &keyId) {
+ if (keystore.HaveKey(keyId))
+ vKeys.push_back(keyId);
+ }
+
+ void operator()(const CScriptID &scriptId) {
+ CScript script;
+ if (keystore.GetCScript(scriptId, script))
+ Process(script);
+ }
+
+ void operator()(const WitnessV0ScriptHash& scriptID)
+ {
+ CScriptID id;
+ CRIPEMD160().Write(scriptID.begin(), 32).Finalize(id.begin());
+ CScript script;
+ if (keystore.GetCScript(id, script)) {
+ Process(script);
+ }
+ }
+
+ void operator()(const WitnessV0KeyHash& keyid)
+ {
+ CKeyID id(keyid);
+ if (keystore.HaveKey(id)) {
+ vKeys.push_back(id);
+ }
+ }
+
+ template<typename X>
+ void operator()(const X &none) {}
+};
+
const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
{
LOCK(cs_wallet);
std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(hash);
if (it == mapWallet.end())
- return NULL;
+ return nullptr;
return &(it->second);
}
-CPubKey CWallet::GenerateNewKey()
+CPubKey CWallet::GenerateNewKey(CWalletDB &walletdb, bool internal)
{
AssertLockHeld(cs_wallet); // mapKeyMetadata
bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
@@ -100,34 +155,35 @@ CPubKey CWallet::GenerateNewKey()
// use HD key derivation if HD was enabled during wallet creation
if (IsHDEnabled()) {
- DeriveNewChildKey(metadata, secret);
+ DeriveNewChildKey(walletdb, metadata, secret, (CanSupportFeature(FEATURE_HD_SPLIT) ? internal : false));
} else {
secret.MakeNewKey(fCompressed);
}
// Compressed public keys were introduced in version 0.6.0
- if (fCompressed)
+ if (fCompressed) {
SetMinVersion(FEATURE_COMPRPUBKEY);
+ }
CPubKey pubkey = secret.GetPubKey();
assert(secret.VerifyPubKey(pubkey));
mapKeyMetadata[pubkey.GetID()] = metadata;
- if (!nTimeFirstKey || nCreationTime < nTimeFirstKey)
- nTimeFirstKey = nCreationTime;
+ UpdateTimeFirstKey(nCreationTime);
- if (!AddKeyPubKey(secret, pubkey))
+ if (!AddKeyPubKeyWithDB(walletdb, secret, pubkey)) {
throw std::runtime_error(std::string(__func__) + ": AddKey failed");
+ }
return pubkey;
}
-void CWallet::DeriveNewChildKey(CKeyMetadata& metadata, CKey& secret)
+void CWallet::DeriveNewChildKey(CWalletDB &walletdb, CKeyMetadata& metadata, CKey& secret, bool internal)
{
// for now we use a fixed keypath scheme of m/0'/0'/k
CKey key; //master key seed (256bit)
CExtKey masterKey; //hd master key
CExtKey accountKey; //key at m/0'
- CExtKey externalChainChildKey; //key at m/0'/0'
+ CExtKey chainChildKey; //key at m/0'/0' (external) or m/0'/1' (internal)
CExtKey childKey; //key at m/0'/0'/<n>'
// try to get the master key
@@ -140,59 +196,80 @@ void CWallet::DeriveNewChildKey(CKeyMetadata& metadata, CKey& secret)
// use hardened derivation (child keys >= 0x80000000 are hardened after bip32)
masterKey.Derive(accountKey, BIP32_HARDENED_KEY_LIMIT);
- // derive m/0'/0'
- accountKey.Derive(externalChainChildKey, BIP32_HARDENED_KEY_LIMIT);
+ // derive m/0'/0' (external chain) OR m/0'/1' (internal chain)
+ assert(internal ? CanSupportFeature(FEATURE_HD_SPLIT) : true);
+ accountKey.Derive(chainChildKey, BIP32_HARDENED_KEY_LIMIT+(internal ? 1 : 0));
// derive child key at next index, skip keys already known to the wallet
do {
// always derive hardened keys
// childIndex | BIP32_HARDENED_KEY_LIMIT = derive childIndex in hardened child-index-range
// example: 1 | BIP32_HARDENED_KEY_LIMIT == 0x80000001 == 2147483649
- externalChainChildKey.Derive(childKey, hdChain.nExternalChainCounter | BIP32_HARDENED_KEY_LIMIT);
- metadata.hdKeypath = "m/0'/0'/" + std::to_string(hdChain.nExternalChainCounter) + "'";
- metadata.hdMasterKeyID = hdChain.masterKeyID;
- // increment childkey index
- hdChain.nExternalChainCounter++;
+ if (internal) {
+ chainChildKey.Derive(childKey, hdChain.nInternalChainCounter | BIP32_HARDENED_KEY_LIMIT);
+ metadata.hdKeypath = "m/0'/1'/" + std::to_string(hdChain.nInternalChainCounter) + "'";
+ hdChain.nInternalChainCounter++;
+ }
+ else {
+ chainChildKey.Derive(childKey, hdChain.nExternalChainCounter | BIP32_HARDENED_KEY_LIMIT);
+ metadata.hdKeypath = "m/0'/0'/" + std::to_string(hdChain.nExternalChainCounter) + "'";
+ hdChain.nExternalChainCounter++;
+ }
} while (HaveKey(childKey.key.GetPubKey().GetID()));
secret = childKey.key;
-
+ metadata.hdMasterKeyID = hdChain.masterKeyID;
// update the chain model in the database
- if (!CWalletDB(strWalletFile).WriteHDChain(hdChain))
+ if (!walletdb.WriteHDChain(hdChain))
throw std::runtime_error(std::string(__func__) + ": Writing HD chain model failed");
}
-bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
+bool CWallet::AddKeyPubKeyWithDB(CWalletDB &walletdb, const CKey& secret, const CPubKey &pubkey)
{
AssertLockHeld(cs_wallet); // mapKeyMetadata
- if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey))
+
+ // CCryptoKeyStore has no concept of wallet databases, but calls AddCryptedKey
+ // which is overridden below. To avoid flushes, the database handle is
+ // tunneled through to it.
+ bool needsDB = !pwalletdbEncryption;
+ if (needsDB) {
+ pwalletdbEncryption = &walletdb;
+ }
+ if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey)) {
+ if (needsDB) pwalletdbEncryption = nullptr;
return false;
+ }
+ if (needsDB) pwalletdbEncryption = nullptr;
// check if we need to remove from watch-only
CScript script;
script = GetScriptForDestination(pubkey.GetID());
- if (HaveWatchOnly(script))
+ if (HaveWatchOnly(script)) {
RemoveWatchOnly(script);
+ }
script = GetScriptForRawPubKey(pubkey);
- if (HaveWatchOnly(script))
+ if (HaveWatchOnly(script)) {
RemoveWatchOnly(script);
+ }
- if (!fFileBacked)
- return true;
if (!IsCrypted()) {
- return CWalletDB(strWalletFile).WriteKey(pubkey,
+ return walletdb.WriteKey(pubkey,
secret.GetPrivKey(),
mapKeyMetadata[pubkey.GetID()]);
}
return true;
}
+bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
+{
+ CWalletDB walletdb(*dbw);
+ return CWallet::AddKeyPubKeyWithDB(walletdb, secret, pubkey);
+}
+
bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
- const vector<unsigned char> &vchCryptedSecret)
+ const std::vector<unsigned char> &vchCryptedSecret)
{
if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
return false;
- if (!fFileBacked)
- return true;
{
LOCK(cs_wallet);
if (pwalletdbEncryption)
@@ -200,20 +277,17 @@ bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
vchCryptedSecret,
mapKeyMetadata[vchPubKey.GetID()]);
else
- return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey,
+ return CWalletDB(*dbw).WriteCryptedKey(vchPubKey,
vchCryptedSecret,
mapKeyMetadata[vchPubKey.GetID()]);
}
- return false;
}
-bool CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta)
+bool CWallet::LoadKeyMetadata(const CTxDestination& keyID, const CKeyMetadata &meta)
{
AssertLockHeld(cs_wallet); // mapKeyMetadata
- if (meta.nCreateTime && (!nTimeFirstKey || meta.nCreateTime < nTimeFirstKey))
- nTimeFirstKey = meta.nCreateTime;
-
- mapKeyMetadata[pubkey.GetID()] = meta;
+ UpdateTimeFirstKey(meta.nCreateTime);
+ mapKeyMetadata[keyID] = meta;
return true;
}
@@ -222,13 +296,27 @@ bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigne
return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
}
+/**
+ * Update wallet first key creation time. This should be called whenever keys
+ * are added to the wallet, with the oldest key creation time.
+ */
+void CWallet::UpdateTimeFirstKey(int64_t nCreateTime)
+{
+ AssertLockHeld(cs_wallet);
+ if (nCreateTime <= 1) {
+ // Cannot determine birthday information, so set the wallet birthday to
+ // the beginning of time.
+ nTimeFirstKey = 1;
+ } else if (!nTimeFirstKey || nCreateTime < nTimeFirstKey) {
+ nTimeFirstKey = nCreateTime;
+ }
+}
+
bool CWallet::AddCScript(const CScript& redeemScript)
{
if (!CCryptoKeyStore::AddCScript(redeemScript))
return false;
- if (!fFileBacked)
- return true;
- return CWalletDB(strWalletFile).WriteCScript(Hash160(redeemScript), redeemScript);
+ return CWalletDB(*dbw).WriteCScript(Hash160(redeemScript), redeemScript);
}
bool CWallet::LoadCScript(const CScript& redeemScript)
@@ -238,7 +326,7 @@ bool CWallet::LoadCScript(const CScript& redeemScript)
* these. Do not add them to the wallet and warn. */
if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
{
- std::string strAddr = CBitcoinAddress(CScriptID(redeemScript)).ToString();
+ std::string strAddr = EncodeDestination(CScriptID(redeemScript));
LogPrintf("%s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n",
__func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr);
return true;
@@ -247,15 +335,20 @@ bool CWallet::LoadCScript(const CScript& redeemScript)
return CCryptoKeyStore::AddCScript(redeemScript);
}
-bool CWallet::AddWatchOnly(const CScript &dest)
+bool CWallet::AddWatchOnly(const CScript& dest)
{
if (!CCryptoKeyStore::AddWatchOnly(dest))
return false;
- nTimeFirstKey = 1; // No birthday information for watch-only keys.
+ const CKeyMetadata& meta = mapKeyMetadata[CScriptID(dest)];
+ UpdateTimeFirstKey(meta.nCreateTime);
NotifyWatchonlyChanged(true);
- if (!fFileBacked)
- return true;
- return CWalletDB(strWalletFile).WriteWatchOnly(dest);
+ return CWalletDB(*dbw).WriteWatchOnly(dest, meta);
+}
+
+bool CWallet::AddWatchOnly(const CScript& dest, int64_t nCreateTime)
+{
+ mapKeyMetadata[CScriptID(dest)].nCreateTime = nCreateTime;
+ return AddWatchOnly(dest);
}
bool CWallet::RemoveWatchOnly(const CScript &dest)
@@ -265,9 +358,8 @@ bool CWallet::RemoveWatchOnly(const CScript &dest)
return false;
if (!HaveWatchOnly())
NotifyWatchonlyChanged(false);
- if (fFileBacked)
- if (!CWalletDB(strWalletFile).EraseWatchOnly(dest))
- return false;
+ if (!CWalletDB(*dbw).EraseWatchOnly(dest))
+ return false;
return true;
}
@@ -280,17 +372,17 @@ bool CWallet::LoadWatchOnly(const CScript &dest)
bool CWallet::Unlock(const SecureString& strWalletPassphrase)
{
CCrypter crypter;
- CKeyingMaterial vMasterKey;
+ CKeyingMaterial _vMasterKey;
{
LOCK(cs_wallet);
- BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
+ for (const MasterKeyMap::value_type& pMasterKey : mapMasterKeys)
{
if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false;
- if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
+ if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
continue; // try another master key
- if (CCryptoKeyStore::Unlock(vMasterKey))
+ if (CCryptoKeyStore::Unlock(_vMasterKey))
return true;
}
}
@@ -306,22 +398,22 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
Lock();
CCrypter crypter;
- CKeyingMaterial vMasterKey;
- BOOST_FOREACH(MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
+ CKeyingMaterial _vMasterKey;
+ for (MasterKeyMap::value_type& pMasterKey : mapMasterKeys)
{
if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false;
- if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
+ if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
return false;
- if (CCryptoKeyStore::Unlock(vMasterKey))
+ if (CCryptoKeyStore::Unlock(_vMasterKey))
{
int64_t nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
- pMasterKey.second.nDeriveIterations = pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime)));
+ pMasterKey.second.nDeriveIterations = static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime))));
nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
- pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
+ pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime)))) / 2;
if (pMasterKey.second.nDeriveIterations < 25000)
pMasterKey.second.nDeriveIterations = 25000;
@@ -330,9 +422,9 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false;
- if (!crypter.Encrypt(vMasterKey, pMasterKey.second.vchCryptedKey))
+ if (!crypter.Encrypt(_vMasterKey, pMasterKey.second.vchCryptedKey))
return false;
- CWalletDB(strWalletFile).WriteMasterKey(pMasterKey.first, pMasterKey.second);
+ CWalletDB(*dbw).WriteMasterKey(pMasterKey.first, pMasterKey.second);
if (fWasLocked)
Lock();
return true;
@@ -345,7 +437,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
void CWallet::SetBestChain(const CBlockLocator& loc)
{
- CWalletDB walletdb(strWalletFile);
+ CWalletDB walletdb(*dbw);
walletdb.WriteBestBlock(loc);
}
@@ -364,9 +456,8 @@ bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn,
if (nVersion > nWalletMaxVersion)
nWalletMaxVersion = nVersion;
- if (fFileBacked)
{
- CWalletDB* pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB(strWalletFile);
+ CWalletDB* pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB(*dbw);
if (nWalletVersion > 40000)
pwalletdb->WriteMinVersion(nWalletVersion);
if (!pwalletdbIn)
@@ -388,9 +479,9 @@ bool CWallet::SetMaxVersion(int nVersion)
return true;
}
-set<uint256> CWallet::GetConflicts(const uint256& txid) const
+std::set<uint256> CWallet::GetConflicts(const uint256& txid) const
{
- set<uint256> result;
+ std::set<uint256> result;
AssertLockHeld(cs_wallet);
std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(txid);
@@ -400,7 +491,7 @@ set<uint256> CWallet::GetConflicts(const uint256& txid) const
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
- BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
+ for (const CTxIn& txin : wtx.tx->vin)
{
if (mapTxSpends.count(txin.prevout) <= 1)
continue; // No conflict if zero or one spends
@@ -411,78 +502,26 @@ set<uint256> CWallet::GetConflicts(const uint256& txid) const
return result;
}
-void CWallet::Flush(bool shutdown)
+bool CWallet::HasWalletSpend(const uint256& txid) const
{
- bitdb.Flush(shutdown);
+ AssertLockHeld(cs_wallet);
+ auto iter = mapTxSpends.lower_bound(COutPoint(txid, 0));
+ return (iter != mapTxSpends.end() && iter->first.hash == txid);
}
-bool CWallet::Verify()
+void CWallet::Flush(bool shutdown)
{
- if (GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET))
- return true;
-
- LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0));
- std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT);
-
- LogPrintf("Using wallet %s\n", walletFile);
- uiInterface.InitMessage(_("Verifying wallet..."));
-
- // Wallet file must be a plain filename without a directory
- if (walletFile != boost::filesystem::basename(walletFile) + boost::filesystem::extension(walletFile))
- return InitError(strprintf(_("Wallet %s resides outside data directory %s"), walletFile, GetDataDir().string()));
-
- if (!bitdb.Open(GetDataDir()))
- {
- // try moving the database env out of the way
- boost::filesystem::path pathDatabase = GetDataDir() / "database";
- boost::filesystem::path pathDatabaseBak = GetDataDir() / strprintf("database.%d.bak", GetTime());
- try {
- boost::filesystem::rename(pathDatabase, pathDatabaseBak);
- LogPrintf("Moved old %s to %s. Retrying.\n", pathDatabase.string(), pathDatabaseBak.string());
- } catch (const boost::filesystem::filesystem_error&) {
- // failure is ok (well, not really, but it's not worse than what we started with)
- }
-
- // try again
- if (!bitdb.Open(GetDataDir())) {
- // if it still fails, it probably means we can't even create the database env
- return InitError(strprintf(_("Error initializing wallet database environment %s!"), GetDataDir()));
- }
- }
-
- if (GetBoolArg("-salvagewallet", false))
- {
- // Recover readable keypairs:
- if (!CWalletDB::Recover(bitdb, walletFile, true))
- return false;
- }
-
- if (boost::filesystem::exists(GetDataDir() / walletFile))
- {
- CDBEnv::VerifyResult r = bitdb.Verify(walletFile, CWalletDB::Recover);
- if (r == CDBEnv::RECOVER_OK)
- {
- InitWarning(strprintf(_("Warning: Wallet file corrupt, data salvaged!"
- " Original %s saved as %s in %s; if"
- " your balance or transactions are incorrect you should"
- " restore from a backup."),
- walletFile, "wallet.{timestamp}.bak", GetDataDir()));
- }
- if (r == CDBEnv::RECOVER_FAIL)
- return InitError(strprintf(_("%s corrupt, salvage failed"), walletFile));
- }
-
- return true;
+ dbw->Flush(shutdown);
}
-void CWallet::SyncMetaData(pair<TxSpends::iterator, TxSpends::iterator> range)
+void CWallet::SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator> range)
{
// We want all the wallet transactions in range to have the same metadata as
// the oldest (smallest nOrderPos).
// So: find smallest nOrderPos:
int nMinOrderPos = std::numeric_limits<int>::max();
- const CWalletTx* copyFrom = NULL;
+ const CWalletTx* copyFrom = nullptr;
for (TxSpends::iterator it = range.first; it != range.second; ++it)
{
const uint256& hash = it->second;
@@ -499,6 +538,7 @@ void CWallet::SyncMetaData(pair<TxSpends::iterator, TxSpends::iterator> range)
const uint256& hash = it->second;
CWalletTx* copyTo = &mapWallet[hash];
if (copyFrom == copyTo) continue;
+ assert(copyFrom && "Oldest wallet transaction in range assumed to have been found.");
if (!copyFrom->IsEquivalentTo(*copyTo)) continue;
copyTo->mapValue = copyFrom->mapValue;
copyTo->vOrderForm = copyFrom->vOrderForm;
@@ -519,7 +559,7 @@ void CWallet::SyncMetaData(pair<TxSpends::iterator, TxSpends::iterator> range)
bool CWallet::IsSpent(const uint256& hash, unsigned int n) const
{
const COutPoint outpoint(hash, n);
- pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
+ std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
range = mapTxSpends.equal_range(outpoint);
for (TxSpends::const_iterator it = range.first; it != range.second; ++it)
@@ -537,9 +577,9 @@ bool CWallet::IsSpent(const uint256& hash, unsigned int n) const
void CWallet::AddToSpends(const COutPoint& outpoint, const uint256& wtxid)
{
- mapTxSpends.insert(make_pair(outpoint, wtxid));
+ mapTxSpends.insert(std::make_pair(outpoint, wtxid));
- pair<TxSpends::iterator, TxSpends::iterator> range;
+ std::pair<TxSpends::iterator, TxSpends::iterator> range;
range = mapTxSpends.equal_range(outpoint);
SyncMetaData(range);
}
@@ -547,12 +587,13 @@ void CWallet::AddToSpends(const COutPoint& outpoint, const uint256& wtxid)
void CWallet::AddToSpends(const uint256& wtxid)
{
- assert(mapWallet.count(wtxid));
- CWalletTx& thisTx = mapWallet[wtxid];
+ auto it = mapWallet.find(wtxid);
+ assert(it != mapWallet.end());
+ CWalletTx& thisTx = it->second;
if (thisTx.IsCoinBase()) // Coinbases don't spend anything!
return;
- BOOST_FOREACH(const CTxIn& txin, thisTx.tx->vin)
+ for (const CTxIn& txin : thisTx.tx->vin)
AddToSpends(txin.prevout, wtxid);
}
@@ -561,10 +602,10 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
if (IsCrypted())
return false;
- CKeyingMaterial vMasterKey;
+ CKeyingMaterial _vMasterKey;
- vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
- GetStrongRandBytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
+ _vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
+ GetStrongRandBytes(&_vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
CMasterKey kMasterKey;
@@ -574,11 +615,11 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
CCrypter crypter;
int64_t nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
- kMasterKey.nDeriveIterations = 2500000 / ((double)(GetTimeMillis() - nStartTime));
+ kMasterKey.nDeriveIterations = static_cast<unsigned int>(2500000 / ((double)(GetTimeMillis() - nStartTime)));
nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
- kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
+ kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + static_cast<unsigned int>(kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime)))) / 2;
if (kMasterKey.nDeriveIterations < 25000)
kMasterKey.nDeriveIterations = 25000;
@@ -587,30 +628,25 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod))
return false;
- if (!crypter.Encrypt(vMasterKey, kMasterKey.vchCryptedKey))
+ if (!crypter.Encrypt(_vMasterKey, kMasterKey.vchCryptedKey))
return false;
{
LOCK(cs_wallet);
mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
- if (fFileBacked)
- {
- assert(!pwalletdbEncryption);
- pwalletdbEncryption = new CWalletDB(strWalletFile);
- if (!pwalletdbEncryption->TxnBegin()) {
- delete pwalletdbEncryption;
- pwalletdbEncryption = NULL;
- return false;
- }
- pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
+ assert(!pwalletdbEncryption);
+ pwalletdbEncryption = new CWalletDB(*dbw);
+ if (!pwalletdbEncryption->TxnBegin()) {
+ delete pwalletdbEncryption;
+ pwalletdbEncryption = nullptr;
+ return false;
}
+ pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
- if (!EncryptKeys(vMasterKey))
+ if (!EncryptKeys(_vMasterKey))
{
- if (fFileBacked) {
- pwalletdbEncryption->TxnAbort();
- delete pwalletdbEncryption;
- }
+ pwalletdbEncryption->TxnAbort();
+ delete pwalletdbEncryption;
// We now probably have half of our keys encrypted in memory, and half not...
// die and let the user reload the unencrypted wallet.
assert(false);
@@ -619,28 +655,24 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
// Encryption was introduced in version 0.4.0
SetMinVersion(FEATURE_WALLETCRYPT, pwalletdbEncryption, true);
- if (fFileBacked)
- {
- if (!pwalletdbEncryption->TxnCommit()) {
- delete pwalletdbEncryption;
- // We now have keys encrypted in memory, but not on disk...
- // die to avoid confusion and let the user reload the unencrypted wallet.
- assert(false);
- }
-
+ if (!pwalletdbEncryption->TxnCommit()) {
delete pwalletdbEncryption;
- pwalletdbEncryption = NULL;
+ // We now have keys encrypted in memory, but not on disk...
+ // die to avoid confusion and let the user reload the unencrypted wallet.
+ assert(false);
}
+ delete pwalletdbEncryption;
+ pwalletdbEncryption = nullptr;
+
Lock();
Unlock(strWalletPassphrase);
// if we are using HD, replace the HD master key (seed) with a new one
if (IsHDEnabled()) {
- CKey key;
- CPubKey masterPubKey = GenerateNewHDMasterKey();
- if (!SetHDMasterKey(masterPubKey))
+ if (!SetHDMasterKey(GenerateNewHDMasterKey())) {
return false;
+ }
}
NewKeyPool();
@@ -648,7 +680,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
// Need to completely rewrite the wallet file; if we don't, bdb might keep
// bits of the unencrypted private key in slack space in the database file.
- CDB::Rewrite(strWalletFile);
+ dbw->Rewrite();
}
NotifyStatusChanged(this);
@@ -659,26 +691,26 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
DBErrors CWallet::ReorderTransactions()
{
LOCK(cs_wallet);
- CWalletDB walletdb(strWalletFile);
+ CWalletDB walletdb(*dbw);
// Old wallets didn't have any defined order for transactions
// Probably a bad idea to change the output of this
// First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
- typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
- typedef multimap<int64_t, TxPair > TxItems;
+ typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair;
+ typedef std::multimap<int64_t, TxPair > TxItems;
TxItems txByTime;
- for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (std::map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
CWalletTx* wtx = &((*it).second);
- txByTime.insert(make_pair(wtx->nTimeReceived, TxPair(wtx, (CAccountingEntry*)0)));
+ txByTime.insert(std::make_pair(wtx->nTimeReceived, TxPair(wtx, nullptr)));
}
- list<CAccountingEntry> acentries;
+ std::list<CAccountingEntry> acentries;
walletdb.ListAccountCreditDebit("", acentries);
- BOOST_FOREACH(CAccountingEntry& entry, acentries)
+ for (CAccountingEntry& entry : acentries)
{
- txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
+ txByTime.insert(std::make_pair(entry.nTime, TxPair(nullptr, &entry)));
}
nOrderPosNext = 0;
@@ -687,7 +719,7 @@ DBErrors CWallet::ReorderTransactions()
{
CWalletTx *const pwtx = (*it).second.first;
CAccountingEntry *const pacentry = (*it).second.second;
- int64_t& nOrderPos = (pwtx != 0) ? pwtx->nOrderPos : pacentry->nOrderPos;
+ int64_t& nOrderPos = (pwtx != nullptr) ? pwtx->nOrderPos : pacentry->nOrderPos;
if (nOrderPos == -1)
{
@@ -706,7 +738,7 @@ DBErrors CWallet::ReorderTransactions()
else
{
int64_t nOrderPosOff = 0;
- BOOST_FOREACH(const int64_t& nOffsetStart, nOrderPosOffsets)
+ for (const int64_t& nOffsetStart : nOrderPosOffsets)
{
if (nOrderPos >= nOffsetStart)
++nOrderPosOff;
@@ -740,14 +772,14 @@ int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb)
if (pwalletdb) {
pwalletdb->WriteOrderPosNext(nOrderPosNext);
} else {
- CWalletDB(strWalletFile).WriteOrderPosNext(nOrderPosNext);
+ CWalletDB(*dbw).WriteOrderPosNext(nOrderPosNext);
}
return nRet;
}
bool CWallet::AccountMove(std::string strFrom, std::string strTo, CAmount nAmount, std::string strComment)
{
- CWalletDB walletdb(strWalletFile);
+ CWalletDB walletdb(*dbw);
if (!walletdb.TxnBegin())
return false;
@@ -781,7 +813,7 @@ bool CWallet::AccountMove(std::string strFrom, std::string strTo, CAmount nAmoun
bool CWallet::GetAccountPubkey(CPubKey &pubKey, std::string strAccount, bool bForceNew)
{
- CWalletDB walletdb(strWalletFile);
+ CWalletDB walletdb(*dbw);
CAccount account;
walletdb.ReadAccount(strAccount, account);
@@ -792,10 +824,10 @@ bool CWallet::GetAccountPubkey(CPubKey &pubKey, std::string strAccount, bool bFo
else {
// Check if the current key has been used
CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID());
- for (map<uint256, CWalletTx>::iterator it = mapWallet.begin();
+ for (std::map<uint256, CWalletTx>::iterator it = mapWallet.begin();
it != mapWallet.end() && account.vchPubKey.IsValid();
++it)
- BOOST_FOREACH(const CTxOut& txout, (*it).second.tx->vout)
+ for (const CTxOut& txout : (*it).second.tx->vout)
if (txout.scriptPubKey == scriptPubKey) {
bForceNew = true;
break;
@@ -805,7 +837,7 @@ bool CWallet::GetAccountPubkey(CPubKey &pubKey, std::string strAccount, bool bFo
// Generate a new key
if (bForceNew) {
- if (!GetKeyFromPool(account.vchPubKey))
+ if (!GetKeyFromPool(account.vchPubKey, false))
return false;
SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive");
@@ -821,21 +853,50 @@ void CWallet::MarkDirty()
{
{
LOCK(cs_wallet);
- BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
+ for (std::pair<const uint256, CWalletTx>& item : mapWallet)
item.second.MarkDirty();
}
}
+bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash)
+{
+ LOCK(cs_wallet);
+
+ auto mi = mapWallet.find(originalHash);
+
+ // There is a bug if MarkReplaced is not called on an existing wallet transaction.
+ assert(mi != mapWallet.end());
+
+ CWalletTx& wtx = (*mi).second;
+
+ // Ensure for now that we're not overwriting data
+ assert(wtx.mapValue.count("replaced_by_txid") == 0);
+
+ wtx.mapValue["replaced_by_txid"] = newHash.ToString();
+
+ CWalletDB walletdb(*dbw, "r+");
+
+ bool success = true;
+ if (!walletdb.WriteTx(wtx)) {
+ LogPrintf("%s: Updating walletdb tx %s failed", __func__, wtx.GetHash().ToString());
+ success = false;
+ }
+
+ NotifyTransactionChanged(this, originalHash, CT_UPDATED);
+
+ return success;
+}
+
bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
{
LOCK(cs_wallet);
- CWalletDB walletdb(strWalletFile, "r+", fFlushOnClose);
+ CWalletDB walletdb(*dbw, "r+", fFlushOnClose);
uint256 hash = wtxIn.GetHash();
// Inserts only if not already there, returns tx inserted or tx found
- pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn));
+ std::pair<std::map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(std::make_pair(hash, wtxIn));
CWalletTx& wtx = (*ret.first).second;
wtx.BindWallet(this);
bool fInsertedNew = ret.second;
@@ -843,52 +904,8 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
{
wtx.nTimeReceived = GetAdjustedTime();
wtx.nOrderPos = IncOrderPosNext(&walletdb);
- wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0)));
-
- wtx.nTimeSmart = wtx.nTimeReceived;
- if (!wtxIn.hashUnset())
- {
- if (mapBlockIndex.count(wtxIn.hashBlock))
- {
- int64_t latestNow = wtx.nTimeReceived;
- int64_t latestEntry = 0;
- {
- // Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future
- int64_t latestTolerated = latestNow + 300;
- const TxItems & txOrdered = wtxOrdered;
- for (TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
- {
- CWalletTx *const pwtx = (*it).second.first;
- if (pwtx == &wtx)
- continue;
- CAccountingEntry *const pacentry = (*it).second.second;
- int64_t nSmartTime;
- if (pwtx)
- {
- nSmartTime = pwtx->nTimeSmart;
- if (!nSmartTime)
- nSmartTime = pwtx->nTimeReceived;
- }
- else
- nSmartTime = pacentry->nTime;
- if (nSmartTime <= latestTolerated)
- {
- latestEntry = nSmartTime;
- if (nSmartTime > latestNow)
- latestNow = nSmartTime;
- break;
- }
- }
- }
-
- int64_t blocktime = mapBlockIndex[wtxIn.hashBlock]->GetBlockTime();
- wtx.nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
- }
- else
- LogPrintf("AddToWallet(): found %s in block %s not in index\n",
- wtxIn.GetHash().ToString(),
- wtxIn.hashBlock.ToString());
- }
+ wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr)));
+ wtx.nTimeSmart = ComputeTimeSmart(wtx);
AddToSpends(hash);
}
@@ -917,6 +934,15 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
wtx.fFromMe = wtxIn.fFromMe;
fUpdated = true;
}
+ // If we have a witness-stripped version of this transaction, and we
+ // see a new version with a witness, then we must be upgrading a pre-segwit
+ // wallet. Store the new version of the transaction with the witness,
+ // as the stripped-version must be invalid.
+ // TODO: Store all versions of the transaction, instead of just one.
+ if (wtxIn.tx->HasWitness() && !wtx.tx->HasWitness()) {
+ wtx.SetTx(wtxIn.tx);
+ fUpdated = true;
+ }
}
//// debug print
@@ -934,9 +960,9 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED);
// notify an external script when a wallet transaction comes in or is updated
- std::string strCmd = GetArg("-walletnotify", "");
+ std::string strCmd = gArgs.GetArg("-walletnotify", "");
- if ( !strCmd.empty())
+ if (!strCmd.empty())
{
boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
boost::thread t(runCommand, strCmd); // thread runs free
@@ -952,11 +978,12 @@ bool CWallet::LoadToWallet(const CWalletTx& wtxIn)
mapWallet[hash] = wtxIn;
CWalletTx& wtx = mapWallet[hash];
wtx.BindWallet(this);
- wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0)));
+ wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr)));
AddToSpends(hash);
- BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin) {
- if (mapWallet.count(txin.prevout.hash)) {
- CWalletTx& prevtx = mapWallet[txin.prevout.hash];
+ for (const CTxIn& txin : wtx.tx->vin) {
+ auto it = mapWallet.find(txin.prevout.hash);
+ if (it != mapWallet.end()) {
+ CWalletTx& prevtx = it->second;
if (prevtx.nIndex == -1 && !prevtx.hashUnset()) {
MarkConflicted(prevtx.hashBlock, wtx.GetHash());
}
@@ -967,17 +994,26 @@ bool CWallet::LoadToWallet(const CWalletTx& wtxIn)
}
/**
- * Add a transaction to the wallet, or update it.
- * pblock is optional, but should be provided if the transaction is known to be in a block.
+ * Add a transaction to the wallet, or update it. pIndex and posInBlock should
+ * be set when the transaction was known to be included in a block. When
+ * pIndex == nullptr, then wallet state is not updated in AddToWallet, but
+ * notifications happen and cached balances are marked dirty.
+ *
* If fUpdate is true, existing transactions will be updated.
+ * TODO: One exception to this is that the abandoned state is cleared under the
+ * assumption that any further notification of a transaction that was considered
+ * abandoned is an indication that it is not safe to be considered abandoned.
+ * Abandoned state should probably be more carefully tracked via different
+ * posInBlock signals or by checking mempool presence when necessary.
*/
-bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate)
+bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate)
{
+ const CTransaction& tx = *ptx;
{
AssertLockHeld(cs_wallet);
- if (posInBlock != -1) {
- BOOST_FOREACH(const CTxIn& txin, tx.vin) {
+ if (pIndex != nullptr) {
+ for (const CTxIn& txin : tx.vin) {
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.prevout);
while (range.first != range.second) {
if (range.first->second != tx.GetHash()) {
@@ -993,10 +1029,34 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlockIndex
if (fExisted && !fUpdate) return false;
if (fExisted || IsMine(tx) || IsFromMe(tx))
{
- CWalletTx wtx(this, MakeTransactionRef(tx));
+ /* Check if any keys in the wallet keypool that were supposed to be unused
+ * have appeared in a new transaction. If so, remove those keys from the keypool.
+ * This can happen when restoring an old wallet backup that does not contain
+ * the mostly recently created transactions from newer versions of the wallet.
+ */
+
+ // loop though all outputs
+ for (const CTxOut& txout: tx.vout) {
+ // extract addresses and check if they match with an unused keypool key
+ std::vector<CKeyID> vAffected;
+ CAffectedKeysVisitor(*this, vAffected).Process(txout.scriptPubKey);
+ for (const CKeyID &keyid : vAffected) {
+ std::map<CKeyID, int64_t>::const_iterator mi = m_pool_key_to_index.find(keyid);
+ if (mi != m_pool_key_to_index.end()) {
+ LogPrintf("%s: Detected a used keypool key, mark all keypool key up to this key as used\n", __func__);
+ MarkReserveKeysAsUsed(mi->second);
+
+ if (!TopUpKeyPool()) {
+ LogPrintf("%s: Topping up keypool failed (locked wallet)\n", __func__);
+ }
+ }
+ }
+ }
+
+ CWalletTx wtx(this, ptx);
// Get merkle branch if transaction was found in a block
- if (posInBlock != -1)
+ if (pIndex != nullptr)
wtx.SetMerkleBranch(pIndex, posInBlock);
return AddToWallet(wtx, false);
@@ -1005,18 +1065,26 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlockIndex
return false;
}
+bool CWallet::TransactionCanBeAbandoned(const uint256& hashTx) const
+{
+ LOCK2(cs_main, cs_wallet);
+ const CWalletTx* wtx = GetWalletTx(hashTx);
+ return wtx && !wtx->isAbandoned() && wtx->GetDepthInMainChain() <= 0 && !wtx->InMempool();
+}
+
bool CWallet::AbandonTransaction(const uint256& hashTx)
{
LOCK2(cs_main, cs_wallet);
- CWalletDB walletdb(strWalletFile, "r+");
+ CWalletDB walletdb(*dbw, "r+");
std::set<uint256> todo;
std::set<uint256> done;
// Can't mark abandoned if confirmed or in mempool
- assert(mapWallet.count(hashTx));
- CWalletTx& origtx = mapWallet[hashTx];
+ auto it = mapWallet.find(hashTx);
+ assert(it != mapWallet.end());
+ CWalletTx& origtx = it->second;
if (origtx.GetDepthInMainChain() > 0 || origtx.InMempool()) {
return false;
}
@@ -1027,8 +1095,9 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
uint256 now = *todo.begin();
todo.erase(now);
done.insert(now);
- assert(mapWallet.count(now));
- CWalletTx& wtx = mapWallet[now];
+ auto it = mapWallet.find(now);
+ assert(it != mapWallet.end());
+ CWalletTx& wtx = it->second;
int currentconfirm = wtx.GetDepthInMainChain();
// If the orig tx was not in block, none of its spends can be
assert(currentconfirm <= 0);
@@ -1051,10 +1120,12 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
}
// If a transaction changes 'conflicted' state, that changes the balance
// available of the outputs it spends. So force those to be recomputed
- BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
+ for (const CTxIn& txin : wtx.tx->vin)
{
- if (mapWallet.count(txin.prevout.hash))
- mapWallet[txin.prevout.hash].MarkDirty();
+ auto it = mapWallet.find(txin.prevout.hash);
+ if (it != mapWallet.end()) {
+ it->second.MarkDirty();
+ }
}
}
}
@@ -1081,7 +1152,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
return;
// Do not flush the wallet here for performance reasons
- CWalletDB walletdb(strWalletFile, "r+", false);
+ CWalletDB walletdb(*dbw, "r+", false);
std::set<uint256> todo;
std::set<uint256> done;
@@ -1092,8 +1163,9 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
uint256 now = *todo.begin();
todo.erase(now);
done.insert(now);
- assert(mapWallet.count(now));
- CWalletTx& wtx = mapWallet[now];
+ auto it = mapWallet.find(now);
+ assert(it != mapWallet.end());
+ CWalletTx& wtx = it->second;
int currentconfirm = wtx.GetDepthInMainChain();
if (conflictconfirms < currentconfirm) {
// Block is 'more conflicted' than current confirm; update.
@@ -1112,38 +1184,71 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
}
// If a transaction changes 'conflicted' state, that changes the balance
// available of the outputs it spends. So force those to be recomputed
- BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
- {
- if (mapWallet.count(txin.prevout.hash))
- mapWallet[txin.prevout.hash].MarkDirty();
+ for (const CTxIn& txin : wtx.tx->vin) {
+ auto it = mapWallet.find(txin.prevout.hash);
+ if (it != mapWallet.end()) {
+ it->second.MarkDirty();
+ }
}
}
}
}
-void CWallet::SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, int posInBlock)
-{
- LOCK2(cs_main, cs_wallet);
+void CWallet::SyncTransaction(const CTransactionRef& ptx, const CBlockIndex *pindex, int posInBlock) {
+ const CTransaction& tx = *ptx;
- if (!AddToWalletIfInvolvingMe(tx, pindex, posInBlock, true))
+ if (!AddToWalletIfInvolvingMe(ptx, pindex, posInBlock, true))
return; // Not one of ours
// If a transaction changes 'conflicted' state, that changes the balance
// available of the outputs it spends. So force those to be
// recomputed, also:
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
- {
- if (mapWallet.count(txin.prevout.hash))
- mapWallet[txin.prevout.hash].MarkDirty();
+ for (const CTxIn& txin : tx.vin) {
+ auto it = mapWallet.find(txin.prevout.hash);
+ if (it != mapWallet.end()) {
+ it->second.MarkDirty();
+ }
+ }
+}
+
+void CWallet::TransactionAddedToMempool(const CTransactionRef& ptx) {
+ LOCK2(cs_main, cs_wallet);
+ SyncTransaction(ptx);
+}
+
+void CWallet::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) {
+ LOCK2(cs_main, cs_wallet);
+ // TODO: Temporarily ensure that mempool removals are notified before
+ // connected transactions. This shouldn't matter, but the abandoned
+ // state of transactions in our wallet is currently cleared when we
+ // receive another notification and there is a race condition where
+ // notification of a connected conflict might cause an outside process
+ // to abandon a transaction and then have it inadvertently cleared by
+ // the notification that the conflicted transaction was evicted.
+
+ for (const CTransactionRef& ptx : vtxConflicted) {
+ SyncTransaction(ptx);
+ }
+ for (size_t i = 0; i < pblock->vtx.size(); i++) {
+ SyncTransaction(pblock->vtx[i], pindex, i);
}
}
+void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) {
+ LOCK2(cs_main, cs_wallet);
+
+ for (const CTransactionRef& ptx : pblock->vtx) {
+ SyncTransaction(ptx);
+ }
+}
+
+
isminetype CWallet::IsMine(const CTxIn &txin) const
{
{
LOCK(cs_wallet);
- map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
+ std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
if (mi != mapWallet.end())
{
const CWalletTx& prev = (*mi).second;
@@ -1154,11 +1259,13 @@ isminetype CWallet::IsMine(const CTxIn &txin) const
return ISMINE_NO;
}
+// Note that this function doesn't distinguish between a 0-valued input,
+// and a not-"is mine" (according to the filter) input.
CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const
{
{
LOCK(cs_wallet);
- map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
+ std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
if (mi != mapWallet.end())
{
const CWalletTx& prev = (*mi).second;
@@ -1213,7 +1320,7 @@ CAmount CWallet::GetChange(const CTxOut& txout) const
bool CWallet::IsMine(const CTransaction& tx) const
{
- BOOST_FOREACH(const CTxOut& txout, tx.vout)
+ for (const CTxOut& txout : tx.vout)
if (IsMine(txout))
return true;
return false;
@@ -1227,7 +1334,7 @@ bool CWallet::IsFromMe(const CTransaction& tx) const
CAmount CWallet::GetDebit(const CTransaction& tx, const isminefilter& filter) const
{
CAmount nDebit = 0;
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ for (const CTxIn& txin : tx.vin)
{
nDebit += GetDebit(txin, filter);
if (!MoneyRange(nDebit))
@@ -1236,10 +1343,31 @@ CAmount CWallet::GetDebit(const CTransaction& tx, const isminefilter& filter) co
return nDebit;
}
+bool CWallet::IsAllFromMe(const CTransaction& tx, const isminefilter& filter) const
+{
+ LOCK(cs_wallet);
+
+ for (const CTxIn& txin : tx.vin)
+ {
+ auto mi = mapWallet.find(txin.prevout.hash);
+ if (mi == mapWallet.end())
+ return false; // any unknown inputs can't be from us
+
+ const CWalletTx& prev = (*mi).second;
+
+ if (txin.prevout.n >= prev.tx->vout.size())
+ return false; // invalid input!
+
+ if (!(IsMine(prev.tx->vout[txin.prevout.n]) & filter))
+ return false;
+ }
+ return true;
+}
+
CAmount CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter) const
{
CAmount nCredit = 0;
- BOOST_FOREACH(const CTxOut& txout, tx.vout)
+ for (const CTxOut& txout : tx.vout)
{
nCredit += GetCredit(txout, filter);
if (!MoneyRange(nCredit))
@@ -1251,7 +1379,7 @@ CAmount CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter) c
CAmount CWallet::GetChange(const CTransaction& tx) const
{
CAmount nChange = 0;
- BOOST_FOREACH(const CTxOut& txout, tx.vout)
+ for (const CTxOut& txout : tx.vout)
{
nChange += GetChange(txout);
if (!MoneyRange(nChange))
@@ -1293,14 +1421,11 @@ CPubKey CWallet::GenerateNewHDMasterKey()
bool CWallet::SetHDMasterKey(const CPubKey& pubkey)
{
LOCK(cs_wallet);
-
- // ensure this wallet.dat can only be opened by clients supporting HD
- SetMinVersion(FEATURE_HD);
-
// store the keyid (hash160) together with
// the child index counter in the database
// as a hdchain object
CHDChain newHdChain;
+ newHdChain.nVersion = CanSupportFeature(FEATURE_HD_SPLIT) ? CHDChain::VERSION_HD_CHAIN_SPLIT : CHDChain::VERSION_HD_BASE;
newHdChain.masterKeyID = pubkey.GetID();
SetHDChain(newHdChain, false);
@@ -1310,14 +1435,14 @@ bool CWallet::SetHDMasterKey(const CPubKey& pubkey)
bool CWallet::SetHDChain(const CHDChain& chain, bool memonly)
{
LOCK(cs_wallet);
- if (!memonly && !CWalletDB(strWalletFile).WriteHDChain(chain))
- throw runtime_error(std::string(__func__) + ": writing chain failed");
+ if (!memonly && !CWalletDB(*dbw).WriteHDChain(chain))
+ throw std::runtime_error(std::string(__func__) + ": writing chain failed");
hdChain = chain;
return true;
}
-bool CWallet::IsHDEnabled()
+bool CWallet::IsHDEnabled() const
{
return !hdChain.masterKeyID.IsNull();
}
@@ -1339,7 +1464,7 @@ int CWalletTx::GetRequestCount() const
// Generated block
if (!hashUnset())
{
- map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
+ std::map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
if (mi != pwallet->mapRequestCount.end())
nRequests = (*mi).second;
}
@@ -1347,7 +1472,7 @@ int CWalletTx::GetRequestCount() const
else
{
// Did anyone request this transaction?
- map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(GetHash());
+ std::map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(GetHash());
if (mi != pwallet->mapRequestCount.end())
{
nRequests = (*mi).second;
@@ -1355,7 +1480,7 @@ int CWalletTx::GetRequestCount() const
// How about the block it's in?
if (nRequests == 0 && !hashUnset())
{
- map<uint256, int>::const_iterator _mi = pwallet->mapRequestCount.find(hashBlock);
+ std::map<uint256, int>::const_iterator _mi = pwallet->mapRequestCount.find(hashBlock);
if (_mi != pwallet->mapRequestCount.end())
nRequests = (*_mi).second;
else
@@ -1367,8 +1492,8 @@ int CWalletTx::GetRequestCount() const
return nRequests;
}
-void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
- list<COutputEntry>& listSent, CAmount& nFee, string& strSentAccount, const isminefilter& filter) const
+void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,
+ std::list<COutputEntry>& listSent, CAmount& nFee, std::string& strSentAccount, const isminefilter& filter) const
{
nFee = 0;
listReceived.clear();
@@ -1423,84 +1548,83 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
}
-void CWalletTx::GetAccountAmounts(const string& strAccount, CAmount& nReceived,
- CAmount& nSent, CAmount& nFee, const isminefilter& filter) const
+/**
+ * Scan active chain for relevant transactions after importing keys. This should
+ * be called whenever new keys are added to the wallet, with the oldest key
+ * creation time.
+ *
+ * @return Earliest timestamp that could be successfully scanned from. Timestamp
+ * returned will be higher than startTime if relevant blocks could not be read.
+ */
+int64_t CWallet::RescanFromTime(int64_t startTime, bool update)
{
- nReceived = nSent = nFee = 0;
+ AssertLockHeld(cs_main);
+ AssertLockHeld(cs_wallet);
- CAmount allFee;
- string strSentAccount;
- list<COutputEntry> listReceived;
- list<COutputEntry> listSent;
- GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
+ // Find starting block. May be null if nCreateTime is greater than the
+ // highest blockchain timestamp, in which case there is nothing that needs
+ // to be scanned.
+ CBlockIndex* const startBlock = chainActive.FindEarliestAtLeast(startTime - TIMESTAMP_WINDOW);
+ LogPrintf("%s: Rescanning last %i blocks\n", __func__, startBlock ? chainActive.Height() - startBlock->nHeight + 1 : 0);
- if (strAccount == strSentAccount)
- {
- BOOST_FOREACH(const COutputEntry& s, listSent)
- nSent += s.amount;
- nFee = allFee;
- }
- {
- LOCK(pwallet->cs_wallet);
- BOOST_FOREACH(const COutputEntry& r, listReceived)
- {
- if (pwallet->mapAddressBook.count(r.destination))
- {
- map<CTxDestination, CAddressBookData>::const_iterator mi = pwallet->mapAddressBook.find(r.destination);
- if (mi != pwallet->mapAddressBook.end() && (*mi).second.name == strAccount)
- nReceived += r.amount;
- }
- else if (strAccount.empty())
- {
- nReceived += r.amount;
- }
+ if (startBlock) {
+ const CBlockIndex* const failedBlock = ScanForWalletTransactions(startBlock, update);
+ if (failedBlock) {
+ return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1;
}
}
+ return startTime;
}
/**
* Scan the block chain (starting in pindexStart) for transactions
* from or to us. If fUpdate is true, found transactions that already
* exist in the wallet will be updated.
+ *
+ * Returns null if scan was successful. Otherwise, if a complete rescan was not
+ * possible (due to pruning or corruption), returns pointer to the most recent
+ * block that could not be scanned.
*/
-int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
+CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
{
- int ret = 0;
int64_t nNow = GetTime();
const CChainParams& chainParams = Params();
CBlockIndex* pindex = pindexStart;
+ CBlockIndex* ret = nullptr;
{
LOCK2(cs_main, cs_wallet);
-
- // no need to read and scan block, if block was created before
- // our wallet birthday (as adjusted for block time variability)
- while (pindex && nTimeFirstKey && (pindex->GetBlockTime() < (nTimeFirstKey - 7200)))
- pindex = chainActive.Next(pindex);
+ fAbortRescan = false;
+ fScanningWallet = true;
ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
double dProgressStart = GuessVerificationProgress(chainParams.TxData(), pindex);
double dProgressTip = GuessVerificationProgress(chainParams.TxData(), chainActive.Tip());
- while (pindex)
+ while (pindex && !fAbortRescan)
{
if (pindex->nHeight % 100 == 0 && dProgressTip - dProgressStart > 0.0)
ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((GuessVerificationProgress(chainParams.TxData(), pindex) - dProgressStart) / (dProgressTip - dProgressStart) * 100))));
-
- CBlock block;
- ReadBlockFromDisk(block, pindex, Params().GetConsensus());
- int posInBlock;
- for (posInBlock = 0; posInBlock < (int)block.vtx.size(); posInBlock++)
- {
- if (AddToWalletIfInvolvingMe(*block.vtx[posInBlock], pindex, posInBlock, fUpdate))
- ret++;
- }
- pindex = chainActive.Next(pindex);
if (GetTime() >= nNow + 60) {
nNow = GetTime();
LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, GuessVerificationProgress(chainParams.TxData(), pindex));
}
+
+ CBlock block;
+ if (ReadBlockFromDisk(block, pindex, Params().GetConsensus())) {
+ for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) {
+ AddToWalletIfInvolvingMe(block.vtx[posInBlock], pindex, posInBlock, fUpdate);
+ }
+ } else {
+ ret = pindex;
+ }
+ pindex = chainActive.Next(pindex);
+ }
+ if (pindex && fAbortRescan) {
+ LogPrintf("Rescan aborted at block %d. Progress=%f\n", pindex->nHeight, GuessVerificationProgress(chainParams.TxData(), pindex));
}
ShowProgress(_("Rescanning..."), 100); // hide progress dialog in GUI
+
+ fScanningWallet = false;
}
return ret;
}
@@ -1514,7 +1638,7 @@ void CWallet::ReacceptWalletTransactions()
std::map<int64_t, CWalletTx*> mapSorted;
// Sort pending wallet transactions based on their initial wallet insertion order
- BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
+ for (std::pair<const uint256, CWalletTx>& item : mapWallet)
{
const uint256& wtxid = item.first;
CWalletTx& wtx = item.second;
@@ -1528,7 +1652,7 @@ void CWallet::ReacceptWalletTransactions()
}
// Try to add wallet transactions to memory pool
- BOOST_FOREACH(PAIRTYPE(const int64_t, CWalletTx*)& item, mapSorted)
+ for (std::pair<const int64_t, CWalletTx*>& item : mapSorted)
{
CWalletTx& wtx = *(item.second);
@@ -1560,10 +1684,10 @@ bool CWalletTx::RelayWalletTransaction(CConnman* connman)
return false;
}
-set<uint256> CWalletTx::GetConflicts() const
+std::set<uint256> CWalletTx::GetConflicts() const
{
- set<uint256> result;
- if (pwallet != NULL)
+ std::set<uint256> result;
+ if (pwallet != nullptr)
{
uint256 myHash = GetHash();
result = pwallet->GetConflicts(myHash);
@@ -1652,7 +1776,7 @@ CAmount CWalletTx::GetImmatureCredit(bool fUseCache) const
CAmount CWalletTx::GetAvailableCredit(bool fUseCache) const
{
- if (pwallet == 0)
+ if (pwallet == nullptr)
return 0;
// Must wait until coinbase is safely deep enough in the chain before valuing it
@@ -1671,7 +1795,7 @@ CAmount CWalletTx::GetAvailableCredit(bool fUseCache) const
const CTxOut &txout = tx->vout[i];
nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE);
if (!MoneyRange(nCredit))
- throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
+ throw std::runtime_error(std::string(__func__) + " : value out of range");
}
}
@@ -1696,7 +1820,7 @@ CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool& fUseCache) const
CAmount CWalletTx::GetAvailableWatchOnlyCredit(const bool& fUseCache) const
{
- if (pwallet == 0)
+ if (pwallet == nullptr)
return 0;
// Must wait until coinbase is safely deep enough in the chain before valuing it
@@ -1714,7 +1838,7 @@ CAmount CWalletTx::GetAvailableWatchOnlyCredit(const bool& fUseCache) const
const CTxOut &txout = tx->vout[i];
nCredit += pwallet->GetCredit(txout, ISMINE_WATCH_ONLY);
if (!MoneyRange(nCredit))
- throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
+ throw std::runtime_error(std::string(__func__) + ": value out of range");
}
}
@@ -1735,10 +1859,7 @@ CAmount CWalletTx::GetChange() const
bool CWalletTx::InMempool() const
{
LOCK(mempool.cs);
- if (mempool.exists(GetHash())) {
- return true;
- }
- return false;
+ return mempool.exists(GetHash());
}
bool CWalletTx::IsTrusted() const
@@ -1759,11 +1880,11 @@ bool CWalletTx::IsTrusted() const
return false;
// Trusted if all inputs are from us and are in the mempool:
- BOOST_FOREACH(const CTxIn& txin, tx->vin)
+ for (const CTxIn& txin : tx->vin)
{
// Transactions not sent by us: not trusted
const CWalletTx* parent = pwallet->GetWalletTx(txin.prevout.hash);
- if (parent == NULL)
+ if (parent == nullptr)
return false;
const CTxOut& parentOut = parent->tx->vout[txin.prevout.n];
if (pwallet->IsMine(parentOut) != ISMINE_SPENDABLE)
@@ -1776,8 +1897,8 @@ bool CWalletTx::IsEquivalentTo(const CWalletTx& _tx) const
{
CMutableTransaction tx1 = *this->tx;
CMutableTransaction tx2 = *_tx.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();
+ for (auto& txin : tx1.vin) txin.scriptSig = CScript();
+ for (auto& txin : tx2.vin) txin.scriptSig = CScript();
return CTransaction(tx1) == CTransaction(tx2);
}
@@ -1786,17 +1907,18 @@ std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime, CCon
std::vector<uint256> result;
LOCK(cs_wallet);
+
// Sort them in chronological order
- multimap<unsigned int, CWalletTx*> mapSorted;
- BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
+ std::multimap<unsigned int, CWalletTx*> mapSorted;
+ for (std::pair<const uint256, CWalletTx>& item : mapWallet)
{
CWalletTx& wtx = item.second;
// Don't rebroadcast if newer than nTime:
if (wtx.nTimeReceived > nTime)
continue;
- mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
+ mapSorted.insert(std::make_pair(wtx.nTimeReceived, &wtx));
}
- BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
+ for (std::pair<const unsigned int, CWalletTx*>& item : mapSorted)
{
CWalletTx& wtx = *item.second;
if (wtx.RelayWalletTransaction(connman))
@@ -1844,7 +1966,7 @@ CAmount CWallet::GetBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
- for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
if (pcoin->IsTrusted())
@@ -1860,7 +1982,7 @@ CAmount CWallet::GetUnconfirmedBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
- for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool())
@@ -1875,7 +1997,7 @@ CAmount CWallet::GetImmatureBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
- for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
nTotal += pcoin->GetImmatureCredit();
@@ -1889,7 +2011,7 @@ CAmount CWallet::GetWatchOnlyBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
- for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
if (pcoin->IsTrusted())
@@ -1905,7 +2027,7 @@ CAmount CWallet::GetUnconfirmedWatchOnlyBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
- for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool())
@@ -1920,7 +2042,7 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
- for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
nTotal += pcoin->GetImmatureWatchOnlyCredit();
@@ -1929,13 +2051,74 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const
return nTotal;
}
-void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fIncludeZeroValue) const
+// Calculate total balance in a different way from GetBalance. The biggest
+// difference is that GetBalance sums up all unspent TxOuts paying to the
+// wallet, while this sums up both spent and unspent TxOuts paying to the
+// wallet, and then subtracts the values of TxIns spending from the wallet. This
+// also has fewer restrictions on which unconfirmed transactions are considered
+// trusted.
+CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth, const std::string* account) const
+{
+ LOCK2(cs_main, cs_wallet);
+
+ CAmount balance = 0;
+ for (const auto& entry : mapWallet) {
+ const CWalletTx& wtx = entry.second;
+ const int depth = wtx.GetDepthInMainChain();
+ if (depth < 0 || !CheckFinalTx(*wtx.tx) || wtx.GetBlocksToMaturity() > 0) {
+ continue;
+ }
+
+ // Loop through tx outputs and add incoming payments. For outgoing txs,
+ // treat change outputs specially, as part of the amount debited.
+ CAmount debit = wtx.GetDebit(filter);
+ const bool outgoing = debit > 0;
+ for (const CTxOut& out : wtx.tx->vout) {
+ if (outgoing && IsChange(out)) {
+ debit -= out.nValue;
+ } else if (IsMine(out) & filter && depth >= minDepth && (!account || *account == GetAccountName(out.scriptPubKey))) {
+ balance += out.nValue;
+ }
+ }
+
+ // For outgoing txs, subtract amount debited.
+ if (outgoing && (!account || *account == wtx.strFromAccount)) {
+ balance -= debit;
+ }
+ }
+
+ if (account) {
+ balance += CWalletDB(*dbw).GetAccountCreditDebit(*account);
+ }
+
+ return balance;
+}
+
+CAmount CWallet::GetAvailableBalance(const CCoinControl* coinControl) const
+{
+ LOCK2(cs_main, cs_wallet);
+
+ CAmount balance = 0;
+ std::vector<COutput> vCoins;
+ AvailableCoins(vCoins, true, coinControl);
+ for (const COutput& out : vCoins) {
+ if (out.fSpendable) {
+ balance += out.tx->tx->vout[out.i].nValue;
+ }
+ }
+ return balance;
+}
+
+void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const CCoinControl *coinControl, const CAmount &nMinimumAmount, const CAmount &nMaximumAmount, const CAmount &nMinimumSumAmount, const uint64_t &nMaximumCount, const int &nMinDepth, const int &nMaxDepth) const
{
vCoins.clear();
{
LOCK2(cs_main, cs_wallet);
- for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+
+ CAmount nTotal = 0;
+
+ for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const uint256& wtxid = it->first;
const CWalletTx* pcoin = &(*it).second;
@@ -1943,9 +2126,6 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
if (!CheckFinalTx(*pcoin))
continue;
- if (fOnlyConfirmed && !pcoin->IsTrusted())
- continue;
-
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
continue;
@@ -1958,24 +2138,155 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
if (nDepth == 0 && !pcoin->InMempool())
continue;
+ bool safeTx = pcoin->IsTrusted();
+
+ // We should not consider coins from transactions that are replacing
+ // other transactions.
+ //
+ // Example: There is a transaction A which is replaced by bumpfee
+ // transaction B. In this case, we want to prevent creation of
+ // a transaction B' which spends an output of B.
+ //
+ // Reason: If transaction A were initially confirmed, transactions B
+ // and B' would no longer be valid, so the user would have to create
+ // a new transaction C to replace B'. However, in the case of a
+ // one-block reorg, transactions B' and C might BOTH be accepted,
+ // when the user only wanted one of them. Specifically, there could
+ // be a 1-block reorg away from the chain where transactions A and C
+ // were accepted to another chain where B, B', and C were all
+ // accepted.
+ if (nDepth == 0 && pcoin->mapValue.count("replaces_txid")) {
+ safeTx = false;
+ }
+
+ // Similarly, we should not consider coins from transactions that
+ // have been replaced. In the example above, we would want to prevent
+ // creation of a transaction A' spending an output of A, because if
+ // transaction B were initially confirmed, conflicting with A and
+ // A', we wouldn't want to the user to create a transaction D
+ // intending to replace A', but potentially resulting in a scenario
+ // where A, A', and D could all be accepted (instead of just B and
+ // D, or just A and A' like the user would want).
+ if (nDepth == 0 && pcoin->mapValue.count("replaced_by_txid")) {
+ safeTx = false;
+ }
+
+ if (fOnlySafe && !safeTx) {
+ continue;
+ }
+
+ if (nDepth < nMinDepth || nDepth > nMaxDepth)
+ continue;
+
for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++) {
+ if (pcoin->tx->vout[i].nValue < nMinimumAmount || pcoin->tx->vout[i].nValue > nMaximumAmount)
+ continue;
+
+ if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs && !coinControl->IsSelected(COutPoint((*it).first, i)))
+ continue;
+
+ if (IsLockedCoin((*it).first, i))
+ continue;
+
+ if (IsSpent(wtxid, i))
+ continue;
+
isminetype mine = IsMine(pcoin->tx->vout[i]);
- if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO &&
- !IsLockedCoin((*it).first, i) && (pcoin->tx->vout[i].nValue > 0 || fIncludeZeroValue) &&
- (!coinControl || !coinControl->HasSelected() || coinControl->fAllowOtherInputs || coinControl->IsSelected(COutPoint((*it).first, i))))
- vCoins.push_back(COutput(pcoin, i, nDepth,
- ((mine & ISMINE_SPENDABLE) != ISMINE_NO) ||
- (coinControl && coinControl->fAllowWatchOnly && (mine & ISMINE_WATCH_SOLVABLE) != ISMINE_NO),
- (mine & (ISMINE_SPENDABLE | ISMINE_WATCH_SOLVABLE)) != ISMINE_NO));
+
+ if (mine == ISMINE_NO) {
+ continue;
+ }
+
+ bool fSpendableIn = ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (coinControl && coinControl->fAllowWatchOnly && (mine & ISMINE_WATCH_SOLVABLE) != ISMINE_NO);
+ bool fSolvableIn = (mine & (ISMINE_SPENDABLE | ISMINE_WATCH_SOLVABLE)) != ISMINE_NO;
+
+ vCoins.push_back(COutput(pcoin, i, nDepth, fSpendableIn, fSolvableIn, safeTx));
+
+ // Checks the sum amount of all UTXO's.
+ if (nMinimumSumAmount != MAX_MONEY) {
+ nTotal += pcoin->tx->vout[i].nValue;
+
+ if (nTotal >= nMinimumSumAmount) {
+ return;
+ }
+ }
+
+ // Checks the maximum number of UTXO's.
+ if (nMaximumCount > 0 && vCoins.size() >= nMaximumCount) {
+ return;
+ }
+ }
+ }
+ }
+}
+
+std::map<CTxDestination, std::vector<COutput>> CWallet::ListCoins() const
+{
+ // TODO: Add AssertLockHeld(cs_wallet) here.
+ //
+ // Because the return value from this function contains pointers to
+ // CWalletTx objects, callers to this function really should acquire the
+ // cs_wallet lock before calling it. However, the current caller doesn't
+ // acquire this lock yet. There was an attempt to add the missing lock in
+ // https://github.com/bitcoin/bitcoin/pull/10340, but that change has been
+ // postponed until after https://github.com/bitcoin/bitcoin/pull/10244 to
+ // avoid adding some extra complexity to the Qt code.
+
+ std::map<CTxDestination, std::vector<COutput>> result;
+
+ std::vector<COutput> availableCoins;
+ AvailableCoins(availableCoins);
+
+ LOCK2(cs_main, cs_wallet);
+ for (auto& coin : availableCoins) {
+ CTxDestination address;
+ if (coin.fSpendable &&
+ ExtractDestination(FindNonChangeParentOutput(*coin.tx->tx, coin.i).scriptPubKey, address)) {
+ result[address].emplace_back(std::move(coin));
+ }
+ }
+
+ std::vector<COutPoint> lockedCoins;
+ ListLockedCoins(lockedCoins);
+ for (const auto& output : lockedCoins) {
+ auto it = mapWallet.find(output.hash);
+ if (it != mapWallet.end()) {
+ int depth = it->second.GetDepthInMainChain();
+ if (depth >= 0 && output.n < it->second.tx->vout.size() &&
+ IsMine(it->second.tx->vout[output.n]) == ISMINE_SPENDABLE) {
+ CTxDestination address;
+ if (ExtractDestination(FindNonChangeParentOutput(*it->second.tx, output.n).scriptPubKey, address)) {
+ result[address].emplace_back(
+ &it->second, output.n, depth, true /* spendable */, true /* solvable */, false /* safe */);
+ }
}
}
}
+
+ return result;
}
-static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,unsigned int> > >vValue, const CAmount& nTotalLower, const CAmount& nTargetValue,
- vector<char>& vfBest, CAmount& nBest, int iterations = 1000)
+const CTxOut& CWallet::FindNonChangeParentOutput(const CTransaction& tx, int output) const
{
- vector<char> vfIncluded;
+ const CTransaction* ptx = &tx;
+ int n = output;
+ while (IsChange(ptx->vout[n]) && ptx->vin.size() > 0) {
+ const COutPoint& prevout = ptx->vin[0].prevout;
+ auto it = mapWallet.find(prevout.hash);
+ if (it == mapWallet.end() || it->second.tx->vout.size() <= prevout.n ||
+ !IsMine(it->second.tx->vout[prevout.n])) {
+ break;
+ }
+ ptx = it->second.tx.get();
+ n = prevout.n;
+ }
+ return ptx->vout[n];
+}
+
+static void ApproximateBestSubset(const std::vector<CInputCoin>& vValue, const CAmount& nTotalLower, const CAmount& nTargetValue,
+ std::vector<char>& vfBest, CAmount& nBest, int iterations = 1000)
+{
+ std::vector<char> vfIncluded;
vfBest.assign(vValue.size(), true);
nBest = nTotalLower;
@@ -1997,9 +2308,9 @@ static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,uns
//that the rng is fast. We do not use a constant random sequence,
//because there may be some privacy improvement by making
//the selection random.
- if (nPass == 0 ? insecure_rand.rand32()&1 : !vfIncluded[i])
+ if (nPass == 0 ? insecure_rand.randbool() : !vfIncluded[i])
{
- nTotal += vValue[i].first;
+ nTotal += vValue[i].txout.nValue;
vfIncluded[i] = true;
if (nTotal >= nTargetValue)
{
@@ -2009,7 +2320,7 @@ static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,uns
nBest = nTotal;
vfBest = vfIncluded;
}
- nTotal -= vValue[i].first;
+ nTotal -= vValue[i].txout.nValue;
vfIncluded[i] = false;
}
}
@@ -2018,22 +2329,20 @@ static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,uns
}
}
-bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMine, const int nConfTheirs, const uint64_t nMaxAncestors, vector<COutput> vCoins,
- set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet) const
+bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMine, const int nConfTheirs, const uint64_t nMaxAncestors, std::vector<COutput> vCoins,
+ std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet) const
{
setCoinsRet.clear();
nValueRet = 0;
// List of values less than target
- pair<CAmount, pair<const CWalletTx*,unsigned int> > coinLowestLarger;
- coinLowestLarger.first = std::numeric_limits<CAmount>::max();
- coinLowestLarger.second.first = NULL;
- vector<pair<CAmount, pair<const CWalletTx*,unsigned int> > > vValue;
+ boost::optional<CInputCoin> coinLowestLarger;
+ std::vector<CInputCoin> vValue;
CAmount nTotalLower = 0;
random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
- BOOST_FOREACH(const COutput &output, vCoins)
+ for (const COutput &output : vCoins)
{
if (!output.fSpendable)
continue;
@@ -2047,22 +2356,21 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMin
continue;
int i = output.i;
- CAmount n = pcoin->tx->vout[i].nValue;
- pair<CAmount,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin, i));
+ CInputCoin coin = CInputCoin(pcoin, i);
- if (n == nTargetValue)
+ if (coin.txout.nValue == nTargetValue)
{
- setCoinsRet.insert(coin.second);
- nValueRet += coin.first;
+ setCoinsRet.insert(coin);
+ nValueRet += coin.txout.nValue;
return true;
}
- else if (n < nTargetValue + MIN_CHANGE)
+ else if (coin.txout.nValue < nTargetValue + MIN_CHANGE)
{
vValue.push_back(coin);
- nTotalLower += n;
+ nTotalLower += coin.txout.nValue;
}
- else if (n < coinLowestLarger.first)
+ else if (!coinLowestLarger || coin.txout.nValue < coinLowestLarger->txout.nValue)
{
coinLowestLarger = coin;
}
@@ -2070,27 +2378,27 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMin
if (nTotalLower == nTargetValue)
{
- for (unsigned int i = 0; i < vValue.size(); ++i)
+ for (const auto& input : vValue)
{
- setCoinsRet.insert(vValue[i].second);
- nValueRet += vValue[i].first;
+ setCoinsRet.insert(input);
+ nValueRet += input.txout.nValue;
}
return true;
}
if (nTotalLower < nTargetValue)
{
- if (coinLowestLarger.second.first == NULL)
+ if (!coinLowestLarger)
return false;
- setCoinsRet.insert(coinLowestLarger.second);
- nValueRet += coinLowestLarger.first;
+ setCoinsRet.insert(coinLowestLarger.get());
+ nValueRet += coinLowestLarger->txout.nValue;
return true;
}
// Solve subset sum by stochastic approximation
std::sort(vValue.begin(), vValue.end(), CompareValueOnly());
std::reverse(vValue.begin(), vValue.end());
- vector<char> vfBest;
+ std::vector<char> vfBest;
CAmount nBest;
ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest);
@@ -2099,57 +2407,61 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMin
// If we have a bigger coin and (either the stochastic approximation didn't find a good solution,
// or the next bigger coin is closer), return the bigger coin
- if (coinLowestLarger.second.first &&
- ((nBest != nTargetValue && nBest < nTargetValue + MIN_CHANGE) || coinLowestLarger.first <= nBest))
+ if (coinLowestLarger &&
+ ((nBest != nTargetValue && nBest < nTargetValue + MIN_CHANGE) || coinLowestLarger->txout.nValue <= nBest))
{
- setCoinsRet.insert(coinLowestLarger.second);
- nValueRet += coinLowestLarger.first;
+ setCoinsRet.insert(coinLowestLarger.get());
+ nValueRet += coinLowestLarger->txout.nValue;
}
else {
for (unsigned int i = 0; i < vValue.size(); i++)
if (vfBest[i])
{
- setCoinsRet.insert(vValue[i].second);
- nValueRet += vValue[i].first;
+ setCoinsRet.insert(vValue[i]);
+ nValueRet += vValue[i].txout.nValue;
}
- LogPrint("selectcoins", "SelectCoins() best subset: ");
- for (unsigned int i = 0; i < vValue.size(); i++)
- if (vfBest[i])
- LogPrint("selectcoins", "%s ", FormatMoney(vValue[i].first));
- LogPrint("selectcoins", "total %s\n", FormatMoney(nBest));
+ if (LogAcceptCategory(BCLog::SELECTCOINS)) {
+ LogPrint(BCLog::SELECTCOINS, "SelectCoins() best subset: ");
+ for (unsigned int i = 0; i < vValue.size(); i++) {
+ if (vfBest[i]) {
+ LogPrint(BCLog::SELECTCOINS, "%s ", FormatMoney(vValue[i].txout.nValue));
+ }
+ }
+ LogPrint(BCLog::SELECTCOINS, "total %s\n", FormatMoney(nBest));
+ }
}
return true;
}
-bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl) const
+bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl) const
{
- vector<COutput> vCoins(vAvailableCoins);
+ std::vector<COutput> vCoins(vAvailableCoins);
// coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs)
{
- BOOST_FOREACH(const COutput& out, vCoins)
+ for (const COutput& out : vCoins)
{
if (!out.fSpendable)
continue;
nValueRet += out.tx->tx->vout[out.i].nValue;
- setCoinsRet.insert(make_pair(out.tx, out.i));
+ setCoinsRet.insert(CInputCoin(out.tx, out.i));
}
return (nValueRet >= nTargetValue);
}
// calculate value from preset inputs and store them
- set<pair<const CWalletTx*, uint32_t> > setPresetCoins;
+ std::set<CInputCoin> setPresetCoins;
CAmount nValueFromPresetInputs = 0;
std::vector<COutPoint> vPresetInputs;
if (coinControl)
coinControl->ListSelected(vPresetInputs);
- BOOST_FOREACH(const COutPoint& outpoint, vPresetInputs)
+ for (const COutPoint& outpoint : vPresetInputs)
{
- map<uint256, CWalletTx>::const_iterator it = mapWallet.find(outpoint.hash);
+ std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(outpoint.hash);
if (it != mapWallet.end())
{
const CWalletTx* pcoin = &it->second;
@@ -2157,22 +2469,22 @@ bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount&
if (pcoin->tx->vout.size() <= outpoint.n)
return false;
nValueFromPresetInputs += pcoin->tx->vout[outpoint.n].nValue;
- setPresetCoins.insert(make_pair(pcoin, outpoint.n));
+ setPresetCoins.insert(CInputCoin(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();)
+ for (std::vector<COutput>::iterator it = vCoins.begin(); it != vCoins.end() && coinControl && coinControl->HasSelected();)
{
- if (setPresetCoins.count(make_pair(it->tx, it->i)))
+ if (setPresetCoins.count(CInputCoin(it->tx, it->i)))
it = vCoins.erase(it);
else
++it;
}
- size_t nMaxChainLength = std::min(GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT), GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT));
- bool fRejectLongChains = GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS);
+ size_t nMaxChainLength = std::min(gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT), gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT));
+ bool fRejectLongChains = gArgs.GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS);
bool res = nTargetValue <= nValueFromPresetInputs ||
SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 6, 0, vCoins, setCoinsRet, nValueRet) ||
@@ -2192,9 +2504,33 @@ bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount&
return res;
}
-bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool overrideEstimatedFeeRate, const CFeeRate& specificFeeRate, int& nChangePosInOut, std::string& strFailReason, bool includeWatching, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, const CTxDestination& destChange)
+bool CWallet::SignTransaction(CMutableTransaction &tx)
+{
+ AssertLockHeld(cs_wallet); // mapWallet
+
+ // sign the new tx
+ CTransaction txNewConst(tx);
+ int nIn = 0;
+ for (const auto& input : tx.vin) {
+ std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(input.prevout.hash);
+ if(mi == mapWallet.end() || input.prevout.n >= mi->second.tx->vout.size()) {
+ return false;
+ }
+ const CScript& scriptPubKey = mi->second.tx->vout[input.prevout.n].scriptPubKey;
+ const CAmount& amount = mi->second.tx->vout[input.prevout.n].nValue;
+ SignatureData sigdata;
+ if (!ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, amount, SIGHASH_ALL), scriptPubKey, sigdata)) {
+ return false;
+ }
+ UpdateTransaction(tx, nIn, sigdata);
+ nIn++;
+ }
+ return true;
+}
+
+bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, CCoinControl coinControl)
{
- vector<CRecipient> vecSend;
+ std::vector<CRecipient> vecSend;
// Turn the txout set into a CRecipient vector
for (size_t idx = 0; idx < tx.vout.size(); idx++)
@@ -2204,30 +2540,30 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool ov
vecSend.push_back(recipient);
}
- CCoinControl coinControl;
- coinControl.destChange = destChange;
coinControl.fAllowOtherInputs = true;
- coinControl.fAllowWatchOnly = includeWatching;
- coinControl.fOverrideFeeRate = overrideEstimatedFeeRate;
- coinControl.nFeeRate = specificFeeRate;
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ for (const CTxIn& txin : tx.vin)
coinControl.Select(txin.prevout);
CReserveKey reservekey(this);
CWalletTx wtx;
- if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosInOut, strFailReason, &coinControl, false))
+ if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosInOut, strFailReason, coinControl, false)) {
return false;
+ }
- if (nChangePosInOut != -1)
+ if (nChangePosInOut != -1) {
tx.vout.insert(tx.vout.begin() + nChangePosInOut, wtx.tx->vout[nChangePosInOut]);
+ // we don't have the normal Create/Commit cycle, and don't want to risk reusing change,
+ // so just remove the key from the keypool here.
+ reservekey.KeepKey();
+ }
// Copy output sizes from new transaction; they may have had the fee subtracted from them
for (unsigned int idx = 0; idx < tx.vout.size(); idx++)
tx.vout[idx].nValue = wtx.tx->vout[idx].nValue;
// Add new txins (keeping original txin scriptSig/order)
- BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
+ for (const CTxIn& txin : wtx.tx->vin)
{
if (!coinControl.IsSelected(txin.prevout))
{
@@ -2241,11 +2577,12 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool ov
}
}
+
return true;
}
-bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet,
- int& nChangePosInOut, std::string& strFailReason, const CCoinControl* coinControl, bool sign)
+bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet,
+ int& nChangePosInOut, std::string& strFailReason, const CCoinControl& coin_control, bool sign)
{
CAmount nValue = 0;
int nChangePosRequest = nChangePosInOut;
@@ -2303,15 +2640,51 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
assert(txNew.nLockTime <= (unsigned int)chainActive.Height());
assert(txNew.nLockTime < LOCKTIME_THRESHOLD);
-
+ FeeCalculation feeCalc;
+ CAmount nFeeNeeded;
+ unsigned int nBytes;
{
- set<pair<const CWalletTx*,unsigned int> > setCoins;
+ std::set<CInputCoin> setCoins;
LOCK2(cs_main, cs_wallet);
{
std::vector<COutput> vAvailableCoins;
- AvailableCoins(vAvailableCoins, true, coinControl);
+ AvailableCoins(vAvailableCoins, true, &coin_control);
+
+ // Create change script that will be used if we need change
+ // TODO: pass in scriptChange instead of reservekey so
+ // change transaction isn't always pay-to-bitcoin-address
+ CScript scriptChange;
+
+ // coin control: send change to custom address
+ if (!boost::get<CNoDestination>(&coin_control.destChange)) {
+ scriptChange = GetScriptForDestination(coin_control.destChange);
+ } else { // no coin control: send change to newly generated address
+ // Note: We use a new key here to keep it from being obvious which side is the change.
+ // The drawback is that by not reusing a previous key, the change may be lost if a
+ // backup is restored, if the backup doesn't have the new private key for the change.
+ // If we reused the old key, it would be possible to add code to look for and
+ // rediscover unknown transactions that were written with keys of ours to recover
+ // post-backup change.
+
+ // Reserve a new key pair from key pool
+ CPubKey vchPubKey;
+ bool ret;
+ ret = reservekey.GetReservedKey(vchPubKey, true);
+ if (!ret)
+ {
+ strFailReason = _("Keypool ran out, please call keypoolrefill first");
+ return false;
+ }
+ scriptChange = GetScriptForDestination(vchPubKey.GetID());
+ }
+ CTxOut change_prototype_txout(0, scriptChange);
+ size_t change_prototype_size = GetSerializeSize(change_prototype_txout, SER_DISK, 0);
+
+ CFeeRate discard_rate = GetDiscardRate(::feeEstimator);
nFeeRet = 0;
+ bool pick_new_inputs = true;
+ CAmount nValueIn = 0;
// Start with no fee and loop until there is enough fee
while (true)
{
@@ -2324,7 +2697,6 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
CAmount nValueToSelect = nValue;
if (nSubtractFeeFromAmount == 0)
nValueToSelect += nFeeRet;
- double dPriority = 0;
// vouts to the payees
for (const auto& recipient : vecSend)
{
@@ -2341,7 +2713,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
}
}
- if (txout.IsDust(dustRelayFee))
+ if (IsDust(txout, ::dustRelayFee))
{
if (recipient.fSubtractFeeFromAmount && nFeeRet > 0)
{
@@ -2358,93 +2730,29 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
}
// Choose coins to use
- CAmount nValueIn = 0;
- setCoins.clear();
- if (!SelectCoins(vAvailableCoins, nValueToSelect, setCoins, nValueIn, coinControl))
- {
- strFailReason = _("Insufficient funds");
- return false;
- }
- for (const auto& pcoin : setCoins)
- {
- CAmount nCredit = pcoin.first->tx->vout[pcoin.second].nValue;
- //The coin age after the next block (depth+1) is used instead of the current,
- //reflecting an assumption the user would accept a bit more delay for
- //a chance at a free transaction.
- //But mempool inputs might still be in the mempool, so their age stays 0
- int age = pcoin.first->GetDepthInMainChain();
- assert(age >= 0);
- if (age != 0)
- age += 1;
- dPriority += (double)nCredit * age;
+ if (pick_new_inputs) {
+ nValueIn = 0;
+ setCoins.clear();
+ if (!SelectCoins(vAvailableCoins, nValueToSelect, setCoins, nValueIn, &coin_control))
+ {
+ strFailReason = _("Insufficient funds");
+ return false;
+ }
}
const CAmount nChange = nValueIn - nValueToSelect;
+
if (nChange > 0)
{
// Fill a vout to ourself
- // TODO: pass in scriptChange instead of reservekey so
- // change transaction isn't always pay-to-bitcoin-address
- CScript scriptChange;
-
- // coin control: send change to custom address
- if (coinControl && !boost::get<CNoDestination>(&coinControl->destChange))
- scriptChange = GetScriptForDestination(coinControl->destChange);
-
- // no coin control: send change to newly generated address
- else
- {
- // Note: We use a new key here to keep it from being obvious which side is the change.
- // The drawback is that by not reusing a previous key, the change may be lost if a
- // backup is restored, if the backup doesn't have the new private key for the change.
- // If we reused the old key, it would be possible to add code to look for and
- // rediscover unknown transactions that were written with keys of ours to recover
- // post-backup change.
-
- // Reserve a new key pair from key pool
- CPubKey vchPubKey;
- bool ret;
- ret = reservekey.GetReservedKey(vchPubKey);
- if (!ret)
- {
- strFailReason = _("Keypool ran out, please call keypoolrefill first");
- return false;
- }
-
- scriptChange = GetScriptForDestination(vchPubKey.GetID());
- }
-
CTxOut newTxOut(nChange, scriptChange);
- // We do not move dust-change to fees, because the sender would end up paying more than requested.
- // This would be against the purpose of the all-inclusive feature.
- // So instead we raise the change and deduct from the recipient.
- if (nSubtractFeeFromAmount > 0 && newTxOut.IsDust(dustRelayFee))
- {
- CAmount nDust = newTxOut.GetDustThreshold(dustRelayFee) - newTxOut.nValue;
- newTxOut.nValue += nDust; // raise change until no more dust
- for (unsigned int i = 0; i < vecSend.size(); i++) // subtract from first recipient
- {
- if (vecSend[i].fSubtractFeeFromAmount)
- {
- txNew.vout[i].nValue -= nDust;
- if (txNew.vout[i].IsDust(dustRelayFee))
- {
- strFailReason = _("The transaction amount is too small to send after the fee has been deducted");
- return false;
- }
- break;
- }
- }
- }
-
// Never create dust outputs; if we would, just
// add the dust to the fee.
- if (newTxOut.IsDust(dustRelayFee))
+ if (IsDust(newTxOut, discard_rate))
{
nChangePosInOut = -1;
nFeeRet += nChange;
- reservekey.ReturnKey();
}
else
{
@@ -2459,12 +2767,12 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
return false;
}
- vector<CTxOut>::iterator position = txNew.vout.begin()+nChangePosInOut;
+ std::vector<CTxOut>::iterator position = txNew.vout.begin()+nChangePosInOut;
txNew.vout.insert(position, newTxOut);
}
+ } else {
+ nChangePosInOut = -1;
}
- else
- reservekey.ReturnKey();
// Fill vin
//
@@ -2474,34 +2782,20 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
// BIP125 defines opt-in RBF as any nSequence < maxint-1, so
// we use the highest possible value in that range (maxint-2)
// to avoid conflicting with other possible uses of nSequence,
- // and in the spirit of "smallest posible change from prior
+ // and in the spirit of "smallest possible change from prior
// behavior."
+ const uint32_t nSequence = coin_control.signalRbf ? MAX_BIP125_RBF_SEQUENCE : (CTxIn::SEQUENCE_FINAL - 1);
for (const auto& coin : setCoins)
- txNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second,CScript(),
- std::numeric_limits<unsigned int>::max() - (fWalletRbf ? 2 : 1)));
+ txNew.vin.push_back(CTxIn(coin.outpoint,CScript(),
+ nSequence));
// Fill in dummy signatures for fee calculation.
- int nIn = 0;
- for (const auto& coin : setCoins)
- {
- const CScript& scriptPubKey = coin.first->tx->vout[coin.second].scriptPubKey;
- SignatureData sigdata;
-
- if (!ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata))
- {
- strFailReason = _("Signing transaction failed");
- return false;
- } else {
- UpdateTransaction(txNew, nIn, sigdata);
- }
-
- nIn++;
+ if (!DummySignTx(txNew, setCoins)) {
+ strFailReason = _("Signing transaction failed");
+ return false;
}
- unsigned int nBytes = GetVirtualTransactionSize(txNew);
-
- CTransaction txNewConst(txNew);
- dPriority = txNewConst.ComputePriority(dPriority, nBytes);
+ nBytes = GetVirtualTransactionSize(txNew);
// Remove scriptSigs to eliminate the fee calculation dummy signatures
for (auto& vin : txNew.vin) {
@@ -2509,27 +2803,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
vin.scriptWitness.SetNull();
}
- // Allow to override the default confirmation target over the CoinControl instance
- int currentConfirmationTarget = nTxConfirmTarget;
- if (coinControl && coinControl->nConfirmTarget > 0)
- currentConfirmationTarget = coinControl->nConfirmTarget;
-
- // Can we complete this as a free transaction?
- if (fSendFreeTransactions && nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE)
- {
- // Not enough fee: enough priority?
- double dPriorityNeeded = mempool.estimateSmartPriority(currentConfirmationTarget);
- // Require at least hard-coded AllowFree.
- if (dPriority >= dPriorityNeeded && AllowFree(dPriority))
- break;
- }
-
- CAmount nFeeNeeded = GetMinimumFee(nBytes, currentConfirmationTarget, mempool);
- if (coinControl && nFeeNeeded > 0 && coinControl->nMinimumTotalFee > nFeeNeeded) {
- nFeeNeeded = coinControl->nMinimumTotalFee;
- }
- if (coinControl && coinControl->fOverrideFeeRate)
- nFeeNeeded = coinControl->nFeeRate.GetFee(nBytes);
+ nFeeNeeded = GetMinimumFee(nBytes, coin_control, ::mempool, ::feeEstimator, &feeCalc);
// If we made it here and we aren't even able to meet the relay fee on the next pass, give up
// because we must be at the maximum allowed fee.
@@ -2540,29 +2814,49 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
}
if (nFeeRet >= nFeeNeeded) {
- // Reduce fee to only the needed amount if we have change
- // output to increase. This prevents potential overpayment
- // in fees if the coins selected to meet nFeeNeeded result
- // in a transaction that requires less fee than the prior
- // iteration.
- // TODO: The case where nSubtractFeeFromAmount > 0 remains
- // to be addressed because it requires returning the fee to
- // the payees and not the change output.
- // TODO: The case where there is no change output remains
- // to be addressed so we avoid creating too small an output.
+ // Reduce fee to only the needed amount if possible. This
+ // prevents potential overpayment in fees if the coins
+ // selected to meet nFeeNeeded result in a transaction that
+ // requires less fee than the prior iteration.
+
+ // If we have no change and a big enough excess fee, then
+ // try to construct transaction again only without picking
+ // new inputs. We now know we only need the smaller fee
+ // (because of reduced tx size) and so we should add a
+ // change output. Only try this once.
+ if (nChangePosInOut == -1 && nSubtractFeeFromAmount == 0 && pick_new_inputs) {
+ unsigned int tx_size_with_change = nBytes + change_prototype_size + 2; // Add 2 as a buffer in case increasing # of outputs changes compact size
+ CAmount fee_needed_with_change = GetMinimumFee(tx_size_with_change, coin_control, ::mempool, ::feeEstimator, nullptr);
+ CAmount minimum_value_for_change = GetDustThreshold(change_prototype_txout, discard_rate);
+ if (nFeeRet >= fee_needed_with_change + minimum_value_for_change) {
+ pick_new_inputs = false;
+ nFeeRet = fee_needed_with_change;
+ continue;
+ }
+ }
+
+ // If we have change output already, just increase it
if (nFeeRet > nFeeNeeded && nChangePosInOut != -1 && nSubtractFeeFromAmount == 0) {
CAmount extraFeePaid = nFeeRet - nFeeNeeded;
- vector<CTxOut>::iterator change_position = txNew.vout.begin()+nChangePosInOut;
+ std::vector<CTxOut>::iterator change_position = txNew.vout.begin()+nChangePosInOut;
change_position->nValue += extraFeePaid;
nFeeRet -= extraFeePaid;
}
break; // Done, enough fee included.
}
+ else if (!pick_new_inputs) {
+ // This shouldn't happen, we should have had enough excess
+ // fee to pay for the new output and still meet nFeeNeeded
+ // Or we should have just subtracted fee from recipients and
+ // nFeeNeeded should not have changed
+ strFailReason = _("Transaction fee and change calculation failed");
+ return false;
+ }
// Try to reduce change to include necessary fee
if (nChangePosInOut != -1 && nSubtractFeeFromAmount == 0) {
CAmount additionalFeeNeeded = nFeeNeeded - nFeeRet;
- vector<CTxOut>::iterator change_position = txNew.vout.begin()+nChangePosInOut;
+ std::vector<CTxOut>::iterator change_position = txNew.vout.begin()+nChangePosInOut;
// Only reduce change if remaining amount is still a large enough output.
if (change_position->nValue >= MIN_FINAL_CHANGE + additionalFeeNeeded) {
change_position->nValue -= additionalFeeNeeded;
@@ -2571,22 +2865,30 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
}
}
+ // If subtracting fee from recipients, we now know what fee we
+ // need to subtract, we have no reason to reselect inputs
+ if (nSubtractFeeFromAmount > 0) {
+ pick_new_inputs = false;
+ }
+
// Include more fee and try again.
nFeeRet = nFeeNeeded;
continue;
}
}
+ if (nChangePosInOut == -1) reservekey.ReturnKey(); // Return any reserved key if we don't have change
+
if (sign)
{
CTransaction txNewConst(txNew);
int nIn = 0;
for (const auto& coin : setCoins)
{
- const CScript& scriptPubKey = coin.first->tx->vout[coin.second].scriptPubKey;
+ const CScript& scriptPubKey = coin.txout.scriptPubKey;
SignatureData sigdata;
- if (!ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, coin.first->tx->vout[coin.second].nValue, SIGHASH_ALL), scriptPubKey, sigdata))
+ if (!ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, coin.txout.nValue, SIGHASH_ALL), scriptPubKey, sigdata))
{
strFailReason = _("Signing transaction failed");
return false;
@@ -2609,21 +2911,30 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
}
}
- if (GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) {
+ if (gArgs.GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) {
// Lastly, ensure this tx will pass the mempool's chain limits
LockPoints lp;
- CTxMemPoolEntry entry(wtxNew.tx, 0, 0, 0, 0, 0, false, 0, lp);
+ CTxMemPoolEntry entry(wtxNew.tx, 0, 0, 0, false, 0, lp);
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;
+ size_t nLimitAncestors = gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT);
+ size_t nLimitAncestorSize = gArgs.GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000;
+ size_t nLimitDescendants = gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT);
+ size_t nLimitDescendantSize = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT)*1000;
std::string errString;
if (!mempool.CalculateMemPoolAncestors(entry, setAncestors, nLimitAncestors, nLimitAncestorSize, nLimitDescendants, nLimitDescendantSize, errString)) {
strFailReason = _("Transaction has too long of a mempool chain");
return false;
}
}
+
+ LogPrintf("Fee Calculation: Fee:%d Bytes:%u Needed:%d Tgt:%d (requested %d) Reason:\"%s\" Decay %.5f: Estimation: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n",
+ nFeeRet, nBytes, nFeeNeeded, feeCalc.returnedTarget, feeCalc.desiredTarget, StringForFeeReason(feeCalc.reason), feeCalc.est.decay,
+ feeCalc.est.pass.start, feeCalc.est.pass.end,
+ 100 * feeCalc.est.pass.withinTarget / (feeCalc.est.pass.totalConfirmed + feeCalc.est.pass.inMempool + feeCalc.est.pass.leftMempool),
+ feeCalc.est.pass.withinTarget, feeCalc.est.pass.totalConfirmed, feeCalc.est.pass.inMempool, feeCalc.est.pass.leftMempool,
+ feeCalc.est.fail.start, feeCalc.est.fail.end,
+ 100 * feeCalc.est.fail.withinTarget / (feeCalc.est.fail.totalConfirmed + feeCalc.est.fail.inMempool + feeCalc.est.fail.leftMempool),
+ feeCalc.est.fail.withinTarget, feeCalc.est.fail.totalConfirmed, feeCalc.est.fail.inMempool, feeCalc.est.fail.leftMempool);
return true;
}
@@ -2644,7 +2955,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CCon
AddToWallet(wtxNew);
// Notify that old coins are spent
- BOOST_FOREACH(const CTxIn& txin, wtxNew.tx->vin)
+ for (const CTxIn& txin : wtxNew.tx->vin)
{
CWalletTx &coin = mapWallet[txin.prevout.hash];
coin.BindWallet(this);
@@ -2670,95 +2981,74 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CCon
}
void CWallet::ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries) {
- CWalletDB walletdb(strWalletFile);
+ CWalletDB walletdb(*dbw);
return walletdb.ListAccountCreditDebit(strAccount, entries);
}
bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry)
{
- CWalletDB walletdb(strWalletFile);
+ CWalletDB walletdb(*dbw);
return AddAccountingEntry(acentry, &walletdb);
}
bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, CWalletDB *pwalletdb)
{
- if (!pwalletdb->WriteAccountingEntry_Backend(acentry))
+ if (!pwalletdb->WriteAccountingEntry(++nAccountingEntryNumber, acentry)) {
return false;
+ }
laccentries.push_back(acentry);
CAccountingEntry & entry = laccentries.back();
- wtxOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry)));
+ wtxOrdered.insert(std::make_pair(entry.nOrderPos, TxPair(nullptr, &entry)));
return true;
}
-CAmount CWallet::GetRequiredFee(unsigned int nTxBytes)
-{
- return std::max(minTxFee.GetFee(nTxBytes), ::minRelayTxFee.GetFee(nTxBytes));
-}
-
-CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool)
-{
- // payTxFee is user-set "I want to pay this much"
- CAmount nFeeNeeded = payTxFee.GetFee(nTxBytes);
- // User didn't set: use -txconfirmtarget to estimate...
- if (nFeeNeeded == 0) {
- int estimateFoundTarget = nConfirmTarget;
- nFeeNeeded = pool.estimateSmartFee(nConfirmTarget, &estimateFoundTarget).GetFee(nTxBytes);
- // ... unless we don't have enough mempool data for estimatefee, then use fallbackFee
- if (nFeeNeeded == 0)
- nFeeNeeded = fallbackFee.GetFee(nTxBytes);
- }
- // prevent user from paying a fee below minRelayTxFee or minTxFee
- nFeeNeeded = std::max(nFeeNeeded, GetRequiredFee(nTxBytes));
- // But always obey the maximum
- if (nFeeNeeded > maxTxFee)
- nFeeNeeded = maxTxFee;
- return nFeeNeeded;
-}
-
-
-
-
DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
{
- if (!fFileBacked)
- return DB_LOAD_OK;
+ LOCK2(cs_main, cs_wallet);
+
fFirstRunRet = false;
- DBErrors nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this);
+ DBErrors nLoadWalletRet = CWalletDB(*dbw,"cr+").LoadWallet(this);
if (nLoadWalletRet == DB_NEED_REWRITE)
{
- if (CDB::Rewrite(strWalletFile, "\x04pool"))
+ if (dbw->Rewrite("\x04pool"))
{
- LOCK(cs_wallet);
- setKeyPool.clear();
+ setInternalKeyPool.clear();
+ setExternalKeyPool.clear();
+ m_pool_key_to_index.clear();
// Note: can't top-up keypool here, because wallet is locked.
// User will be prompted to unlock wallet the next operation
// that requires a new key.
}
}
+ // This wallet is in its first run if all of these are empty
+ fFirstRunRet = mapKeys.empty() && mapCryptedKeys.empty() && mapWatchKeys.empty() && setWatchOnly.empty() && mapScripts.empty();
+
if (nLoadWalletRet != DB_LOAD_OK)
return nLoadWalletRet;
- fFirstRunRet = !vchDefaultKey.IsValid();
uiInterface.LoadWallet(this);
return DB_LOAD_OK;
}
-DBErrors CWallet::ZapSelectTx(vector<uint256>& vHashIn, vector<uint256>& vHashOut)
+DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut)
{
- if (!fFileBacked)
- return DB_LOAD_OK;
- DBErrors nZapSelectTxRet = CWalletDB(strWalletFile,"cr+").ZapSelectTx(this, vHashIn, vHashOut);
+ AssertLockHeld(cs_wallet); // mapWallet
+ DBErrors nZapSelectTxRet = CWalletDB(*dbw,"cr+").ZapSelectTx(vHashIn, vHashOut);
+ for (uint256 hash : vHashOut)
+ mapWallet.erase(hash);
+
if (nZapSelectTxRet == DB_NEED_REWRITE)
{
- if (CDB::Rewrite(strWalletFile, "\x04pool"))
+ if (dbw->Rewrite("\x04pool"))
{
- LOCK(cs_wallet);
- setKeyPool.clear();
+ setInternalKeyPool.clear();
+ setExternalKeyPool.clear();
+ m_pool_key_to_index.clear();
// Note: can't top-up keypool here, because wallet is locked.
// User will be prompted to unlock wallet the next operation
// that requires a new key.
@@ -2776,15 +3066,15 @@ DBErrors CWallet::ZapSelectTx(vector<uint256>& vHashIn, vector<uint256>& vHashOu
DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
{
- if (!fFileBacked)
- return DB_LOAD_OK;
- DBErrors nZapWalletTxRet = CWalletDB(strWalletFile,"cr+").ZapWalletTx(this, vWtx);
+ DBErrors nZapWalletTxRet = CWalletDB(*dbw,"cr+").ZapWalletTx(vWtx);
if (nZapWalletTxRet == DB_NEED_REWRITE)
{
- if (CDB::Rewrite(strWalletFile, "\x04pool"))
+ if (dbw->Rewrite("\x04pool"))
{
LOCK(cs_wallet);
- setKeyPool.clear();
+ setInternalKeyPool.clear();
+ setExternalKeyPool.clear();
+ m_pool_key_to_index.clear();
// Note: can't top-up keypool here, because wallet is locked.
// User will be prompted to unlock wallet the next operation
// that requires a new key.
@@ -2798,7 +3088,7 @@ DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
}
-bool CWallet::SetAddressBook(const CTxDestination& address, const string& strName, const string& strPurpose)
+bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& strPurpose)
{
bool fUpdated = false;
{
@@ -2811,11 +3101,9 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const string& strNam
}
NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address) != ISMINE_NO,
strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) );
- if (!fFileBacked)
- return false;
- if (!strPurpose.empty() && !CWalletDB(strWalletFile).WritePurpose(CBitcoinAddress(address).ToString(), strPurpose))
+ if (!strPurpose.empty() && !CWalletDB(*dbw).WritePurpose(EncodeDestination(address), strPurpose))
return false;
- return CWalletDB(strWalletFile).WriteName(CBitcoinAddress(address).ToString(), strName);
+ return CWalletDB(*dbw).WriteName(EncodeDestination(address), strName);
}
bool CWallet::DelAddressBook(const CTxDestination& address)
@@ -2823,65 +3111,91 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
{
LOCK(cs_wallet); // mapAddressBook
- if(fFileBacked)
+ // Delete destdata tuples associated with address
+ std::string strAddress = EncodeDestination(address);
+ for (const std::pair<std::string, std::string> &item : mapAddressBook[address].destdata)
{
- // Delete destdata tuples associated with address
- std::string strAddress = CBitcoinAddress(address).ToString();
- BOOST_FOREACH(const PAIRTYPE(string, string) &item, mapAddressBook[address].destdata)
- {
- CWalletDB(strWalletFile).EraseDestData(strAddress, item.first);
- }
+ CWalletDB(*dbw).EraseDestData(strAddress, item.first);
}
mapAddressBook.erase(address);
}
NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address) != ISMINE_NO, "", CT_DELETED);
- if (!fFileBacked)
- return false;
- CWalletDB(strWalletFile).ErasePurpose(CBitcoinAddress(address).ToString());
- return CWalletDB(strWalletFile).EraseName(CBitcoinAddress(address).ToString());
+ CWalletDB(*dbw).ErasePurpose(EncodeDestination(address));
+ return CWalletDB(*dbw).EraseName(EncodeDestination(address));
}
-bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
+const std::string& CWallet::GetAccountName(const CScript& scriptPubKey) const
{
- if (fFileBacked)
- {
- if (!CWalletDB(strWalletFile).WriteDefaultKey(vchPubKey))
- return false;
+ CTxDestination address;
+ if (ExtractDestination(scriptPubKey, address) && !scriptPubKey.IsUnspendable()) {
+ auto mi = mapAddressBook.find(address);
+ if (mi != mapAddressBook.end()) {
+ return mi->second.name;
+ }
}
- vchDefaultKey = vchPubKey;
- return true;
+ // A scriptPubKey that doesn't have an entry in the address book is
+ // associated with the default account ("").
+ const static std::string DEFAULT_ACCOUNT_NAME;
+ return DEFAULT_ACCOUNT_NAME;
}
/**
* Mark old keypool keys as used,
- * and generate all new keys
+ * and generate all new keys
*/
bool CWallet::NewKeyPool()
{
{
LOCK(cs_wallet);
- CWalletDB walletdb(strWalletFile);
- BOOST_FOREACH(int64_t nIndex, setKeyPool)
+ CWalletDB walletdb(*dbw);
+
+ for (int64_t nIndex : setInternalKeyPool) {
walletdb.ErasePool(nIndex);
- setKeyPool.clear();
+ }
+ setInternalKeyPool.clear();
- if (IsLocked())
- return false;
+ for (int64_t nIndex : setExternalKeyPool) {
+ walletdb.ErasePool(nIndex);
+ }
+ setExternalKeyPool.clear();
- int64_t nKeys = max(GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t)0);
- for (int i = 0; i < nKeys; i++)
- {
- int64_t nIndex = i+1;
- walletdb.WritePool(nIndex, CKeyPool(GenerateNewKey()));
- setKeyPool.insert(nIndex);
+ m_pool_key_to_index.clear();
+
+ if (!TopUpKeyPool()) {
+ return false;
}
- LogPrintf("CWallet::NewKeyPool wrote %d new keys\n", nKeys);
+ LogPrintf("CWallet::NewKeyPool rewrote keypool\n");
}
return true;
}
+size_t CWallet::KeypoolCountExternalKeys()
+{
+ AssertLockHeld(cs_wallet); // setExternalKeyPool
+ return setExternalKeyPool.size();
+}
+
+void CWallet::LoadKeyPool(int64_t nIndex, const CKeyPool &keypool)
+{
+ AssertLockHeld(cs_wallet);
+ if (keypool.fInternal) {
+ setInternalKeyPool.insert(nIndex);
+ } else {
+ setExternalKeyPool.insert(nIndex);
+ }
+ m_max_keypool_index = std::max(m_max_keypool_index, nIndex);
+ m_pool_key_to_index[keypool.vchPubKey.GetID()] = nIndex;
+
+ // If no metadata exists yet, create a default with the pool key's
+ // creation time. Note that this may be overwritten by actually
+ // stored metadata for that key later, which is fine.
+ CKeyID keyid = keypool.vchPubKey.GetID();
+ if (mapKeyMetadata.count(keyid) == 0)
+ mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime);
+}
+
bool CWallet::TopUpKeyPool(unsigned int kpSize)
{
{
@@ -2890,30 +3204,54 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
if (IsLocked())
return false;
- CWalletDB walletdb(strWalletFile);
-
// Top up key pool
unsigned int nTargetSize;
if (kpSize > 0)
nTargetSize = kpSize;
else
- nTargetSize = max(GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t) 0);
+ nTargetSize = std::max(gArgs.GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t) 0);
- while (setKeyPool.size() < (nTargetSize + 1))
+ // count amount of available keys (internal, external)
+ // make sure the keypool of external and internal keys fits the user selected target (-keypool)
+ int64_t missingExternal = std::max(std::max((int64_t) nTargetSize, (int64_t) 1) - (int64_t)setExternalKeyPool.size(), (int64_t) 0);
+ int64_t missingInternal = std::max(std::max((int64_t) nTargetSize, (int64_t) 1) - (int64_t)setInternalKeyPool.size(), (int64_t) 0);
+
+ if (!IsHDEnabled() || !CanSupportFeature(FEATURE_HD_SPLIT))
+ {
+ // don't create extra internal keys
+ missingInternal = 0;
+ }
+ bool internal = false;
+ CWalletDB walletdb(*dbw);
+ for (int64_t i = missingInternal + missingExternal; i--;)
{
- int64_t nEnd = 1;
- if (!setKeyPool.empty())
- nEnd = *(--setKeyPool.end()) + 1;
- if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
- throw runtime_error(std::string(__func__) + ": writing generated key failed");
- setKeyPool.insert(nEnd);
- LogPrintf("keypool added key %d, size=%u\n", nEnd, setKeyPool.size());
+ if (i < missingInternal) {
+ internal = true;
+ }
+
+ assert(m_max_keypool_index < std::numeric_limits<int64_t>::max()); // How in the hell did you use so many keys?
+ int64_t index = ++m_max_keypool_index;
+
+ CPubKey pubkey(GenerateNewKey(walletdb, internal));
+ if (!walletdb.WritePool(index, CKeyPool(pubkey, internal))) {
+ throw std::runtime_error(std::string(__func__) + ": writing generated key failed");
+ }
+
+ if (internal) {
+ setInternalKeyPool.insert(index);
+ } else {
+ setExternalKeyPool.insert(index);
+ }
+ m_pool_key_to_index[pubkey.GetID()] = index;
+ }
+ if (missingInternal + missingExternal > 0) {
+ LogPrintf("keypool added %d keys (%d internal), size=%u (%u internal)\n", missingInternal + missingExternal, missingInternal, setInternalKeyPool.size() + setExternalKeyPool.size(), setInternalKeyPool.size());
}
}
return true;
}
-void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool)
+void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRequestedInternal)
{
nIndex = -1;
keypool.vchPubKey = CPubKey();
@@ -2923,19 +3261,30 @@ void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool)
if (!IsLocked())
TopUpKeyPool();
+ bool fReturningInternal = IsHDEnabled() && CanSupportFeature(FEATURE_HD_SPLIT) && fRequestedInternal;
+ std::set<int64_t>& setKeyPool = fReturningInternal ? setInternalKeyPool : setExternalKeyPool;
+
// Get the oldest key
if(setKeyPool.empty())
return;
- CWalletDB walletdb(strWalletFile);
+ CWalletDB walletdb(*dbw);
+
+ auto it = setKeyPool.begin();
+ nIndex = *it;
+ setKeyPool.erase(it);
+ if (!walletdb.ReadPool(nIndex, keypool)) {
+ throw std::runtime_error(std::string(__func__) + ": read failed");
+ }
+ if (!HaveKey(keypool.vchPubKey.GetID())) {
+ throw std::runtime_error(std::string(__func__) + ": unknown key in key pool");
+ }
+ if (keypool.fInternal != fReturningInternal) {
+ throw std::runtime_error(std::string(__func__) + ": keypool entry misclassified");
+ }
- nIndex = *(setKeyPool.begin());
- setKeyPool.erase(setKeyPool.begin());
- if (!walletdb.ReadPool(nIndex, keypool))
- throw runtime_error(std::string(__func__) + ": read failed");
- if (!HaveKey(keypool.vchPubKey.GetID()))
- throw runtime_error(std::string(__func__) + ": unknown key in key pool");
assert(keypool.vchPubKey.IsValid());
+ m_pool_key_to_index.erase(keypool.vchPubKey.GetID());
LogPrintf("keypool reserve %d\n", nIndex);
}
}
@@ -2943,35 +3292,38 @@ void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool)
void CWallet::KeepKey(int64_t nIndex)
{
// Remove from key pool
- if (fFileBacked)
- {
- CWalletDB walletdb(strWalletFile);
- walletdb.ErasePool(nIndex);
- }
+ CWalletDB walletdb(*dbw);
+ walletdb.ErasePool(nIndex);
LogPrintf("keypool keep %d\n", nIndex);
}
-void CWallet::ReturnKey(int64_t nIndex)
+void CWallet::ReturnKey(int64_t nIndex, bool fInternal, const CPubKey& pubkey)
{
// Return to key pool
{
LOCK(cs_wallet);
- setKeyPool.insert(nIndex);
+ if (fInternal) {
+ setInternalKeyPool.insert(nIndex);
+ } else {
+ setExternalKeyPool.insert(nIndex);
+ }
+ m_pool_key_to_index[pubkey.GetID()] = nIndex;
}
LogPrintf("keypool return %d\n", nIndex);
}
-bool CWallet::GetKeyFromPool(CPubKey& result)
+bool CWallet::GetKeyFromPool(CPubKey& result, bool internal)
{
- int64_t nIndex = 0;
CKeyPool keypool;
{
LOCK(cs_wallet);
- ReserveKeyFromKeyPool(nIndex, keypool);
+ int64_t nIndex = 0;
+ ReserveKeyFromKeyPool(nIndex, keypool, internal);
if (nIndex == -1)
{
if (IsLocked()) return false;
- result = GenerateNewKey();
+ CWalletDB walletdb(*dbw);
+ result = GenerateNewKey(walletdb, internal);
return true;
}
KeepKey(nIndex);
@@ -2980,33 +3332,44 @@ bool CWallet::GetKeyFromPool(CPubKey& result)
return true;
}
-int64_t CWallet::GetOldestKeyPoolTime()
-{
- LOCK(cs_wallet);
-
- // if the keypool is empty, return <NOW>
- if (setKeyPool.empty())
+static int64_t GetOldestKeyTimeInPool(const std::set<int64_t>& setKeyPool, CWalletDB& walletdb) {
+ if (setKeyPool.empty()) {
return GetTime();
+ }
- // load oldest key from keypool, get time and return
CKeyPool keypool;
- CWalletDB walletdb(strWalletFile);
int64_t nIndex = *(setKeyPool.begin());
- if (!walletdb.ReadPool(nIndex, keypool))
- throw runtime_error(std::string(__func__) + ": read oldest key in keypool failed");
+ if (!walletdb.ReadPool(nIndex, keypool)) {
+ throw std::runtime_error(std::string(__func__) + ": read oldest key in keypool failed");
+ }
assert(keypool.vchPubKey.IsValid());
return keypool.nTime;
}
+int64_t CWallet::GetOldestKeyPoolTime()
+{
+ LOCK(cs_wallet);
+
+ CWalletDB walletdb(*dbw);
+
+ // load oldest key from keypool, get time and return
+ int64_t oldestKey = GetOldestKeyTimeInPool(setExternalKeyPool, walletdb);
+ if (IsHDEnabled() && CanSupportFeature(FEATURE_HD_SPLIT)) {
+ oldestKey = std::max(GetOldestKeyTimeInPool(setInternalKeyPool, walletdb), oldestKey);
+ }
+
+ return oldestKey;
+}
+
std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
{
- map<CTxDestination, CAmount> balances;
+ std::map<CTxDestination, CAmount> balances;
{
LOCK(cs_wallet);
- BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet)
+ for (const auto& walletEntry : mapWallet)
{
- CWalletTx *pcoin = &walletEntry.second;
+ const CWalletTx *pcoin = &walletEntry.second;
if (!pcoin->IsTrusted())
continue;
@@ -3038,21 +3401,21 @@ std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
return balances;
}
-set< set<CTxDestination> > CWallet::GetAddressGroupings()
+std::set< std::set<CTxDestination> > CWallet::GetAddressGroupings()
{
AssertLockHeld(cs_wallet); // mapWallet
- set< set<CTxDestination> > groupings;
- set<CTxDestination> grouping;
+ std::set< std::set<CTxDestination> > groupings;
+ std::set<CTxDestination> grouping;
- BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet)
+ for (const auto& walletEntry : mapWallet)
{
- CWalletTx *pcoin = &walletEntry.second;
+ const CWalletTx *pcoin = &walletEntry.second;
if (pcoin->tx->vin.size() > 0)
{
bool any_mine = false;
// group all input addresses with each other
- BOOST_FOREACH(CTxIn txin, pcoin->tx->vin)
+ for (CTxIn txin : pcoin->tx->vin)
{
CTxDestination address;
if(!IsMine(txin)) /* If this input isn't mine, ignore it */
@@ -3066,7 +3429,7 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings()
// group change with input addresses
if (any_mine)
{
- BOOST_FOREACH(CTxOut txout, pcoin->tx->vout)
+ for (CTxOut txout : pcoin->tx->vout)
if (IsChange(txout))
{
CTxDestination txoutAddr;
@@ -3083,11 +3446,11 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings()
}
// group lone addrs by themselves
- for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++)
- if (IsMine(pcoin->tx->vout[i]))
+ for (const auto& txout : pcoin->tx->vout)
+ if (IsMine(txout))
{
CTxDestination address;
- if(!ExtractDestination(pcoin->tx->vout[i].scriptPubKey, address))
+ if(!ExtractDestination(txout.scriptPubKey, address))
continue;
grouping.insert(address);
groupings.insert(grouping);
@@ -3095,20 +3458,20 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings()
}
}
- set< set<CTxDestination>* > uniqueGroupings; // a set of pointers to groups of addresses
- map< CTxDestination, set<CTxDestination>* > setmap; // map addresses to the unique group containing it
- BOOST_FOREACH(set<CTxDestination> _grouping, groupings)
+ std::set< std::set<CTxDestination>* > uniqueGroupings; // a set of pointers to groups of addresses
+ std::map< CTxDestination, std::set<CTxDestination>* > setmap; // map addresses to the unique group containing it
+ for (std::set<CTxDestination> _grouping : groupings)
{
// make a set of all the groups hit by this new group
- set< set<CTxDestination>* > hits;
- map< CTxDestination, set<CTxDestination>* >::iterator it;
- BOOST_FOREACH(CTxDestination address, _grouping)
+ std::set< std::set<CTxDestination>* > hits;
+ std::map< CTxDestination, std::set<CTxDestination>* >::iterator it;
+ for (CTxDestination address : _grouping)
if ((it = setmap.find(address)) != setmap.end())
hits.insert((*it).second);
// merge all hit groups into a new single group and delete old groups
- set<CTxDestination>* merged = new set<CTxDestination>(_grouping);
- BOOST_FOREACH(set<CTxDestination>* hit, hits)
+ std::set<CTxDestination>* merged = new std::set<CTxDestination>(_grouping);
+ for (std::set<CTxDestination>* hit : hits)
{
merged->insert(hit->begin(), hit->end());
uniqueGroupings.erase(hit);
@@ -3117,12 +3480,12 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings()
uniqueGroupings.insert(merged);
// update setmap
- BOOST_FOREACH(CTxDestination element, *merged)
+ for (CTxDestination element : *merged)
setmap[element] = merged;
}
- set< set<CTxDestination> > ret;
- BOOST_FOREACH(set<CTxDestination>* uniqueGrouping, uniqueGroupings)
+ std::set< std::set<CTxDestination> > ret;
+ for (std::set<CTxDestination>* uniqueGrouping : uniqueGroupings)
{
ret.insert(*uniqueGrouping);
delete uniqueGrouping;
@@ -3131,62 +3494,32 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings()
return ret;
}
-CAmount CWallet::GetAccountBalance(const std::string& strAccount, int nMinDepth, const isminefilter& filter)
-{
- CWalletDB walletdb(strWalletFile);
- return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
-}
-
-CAmount CWallet::GetAccountBalance(CWalletDB& walletdb, const std::string& strAccount, int nMinDepth, const isminefilter& filter)
-{
- CAmount nBalance = 0;
-
- // Tally wallet transactions
- for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
- {
- const CWalletTx& wtx = (*it).second;
- if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
- continue;
-
- CAmount nReceived, nSent, nFee;
- wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
-
- if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
- nBalance += nReceived;
- nBalance -= nSent + nFee;
- }
-
- // Tally internal accounting entries
- nBalance += walletdb.GetAccountCreditDebit(strAccount);
-
- return nBalance;
-}
-
std::set<CTxDestination> CWallet::GetAccountAddresses(const std::string& strAccount) const
{
LOCK(cs_wallet);
- set<CTxDestination> result;
- BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, mapAddressBook)
+ std::set<CTxDestination> result;
+ for (const std::pair<CTxDestination, CAddressBookData>& item : mapAddressBook)
{
const CTxDestination& address = item.first;
- const string& strName = item.second.name;
+ const std::string& strName = item.second.name;
if (strName == strAccount)
result.insert(address);
}
return result;
}
-bool CReserveKey::GetReservedKey(CPubKey& pubkey)
+bool CReserveKey::GetReservedKey(CPubKey& pubkey, bool internal)
{
if (nIndex == -1)
{
CKeyPool keypool;
- pwallet->ReserveKeyFromKeyPool(nIndex, keypool);
+ pwallet->ReserveKeyFromKeyPool(nIndex, keypool, internal);
if (nIndex != -1)
vchPubKey = keypool.vchPubKey;
else {
return false;
}
+ fInternal = keypool.fInternal;
}
assert(vchPubKey.IsValid());
pubkey = vchPubKey;
@@ -3203,46 +3536,39 @@ void CReserveKey::KeepKey()
void CReserveKey::ReturnKey()
{
- if (nIndex != -1)
- pwallet->ReturnKey(nIndex);
+ if (nIndex != -1) {
+ pwallet->ReturnKey(nIndex, fInternal, vchPubKey);
+ }
nIndex = -1;
vchPubKey = CPubKey();
}
-void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) const
+void CWallet::MarkReserveKeysAsUsed(int64_t keypool_id)
{
- setAddress.clear();
+ AssertLockHeld(cs_wallet);
+ bool internal = setInternalKeyPool.count(keypool_id);
+ if (!internal) assert(setExternalKeyPool.count(keypool_id));
+ std::set<int64_t> *setKeyPool = internal ? &setInternalKeyPool : &setExternalKeyPool;
+ auto it = setKeyPool->begin();
- CWalletDB walletdb(strWalletFile);
+ CWalletDB walletdb(*dbw);
+ while (it != std::end(*setKeyPool)) {
+ const int64_t& index = *(it);
+ if (index > keypool_id) break; // set*KeyPool is ordered
- LOCK2(cs_main, cs_wallet);
- BOOST_FOREACH(const int64_t& id, setKeyPool)
- {
CKeyPool keypool;
- if (!walletdb.ReadPool(id, keypool))
- throw runtime_error(std::string(__func__) + ": read failed");
- assert(keypool.vchPubKey.IsValid());
- CKeyID keyID = keypool.vchPubKey.GetID();
- if (!HaveKey(keyID))
- throw runtime_error(std::string(__func__) + ": unknown key in key pool");
- setAddress.insert(keyID);
- }
-}
-
-void CWallet::UpdatedTransaction(const uint256 &hashTx)
-{
- {
- LOCK(cs_wallet);
- // Only notify UI if this transaction is in this wallet
- map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(hashTx);
- if (mi != mapWallet.end())
- NotifyTransactionChanged(this, hashTx, CT_UPDATED);
+ if (walletdb.ReadPool(index, keypool)) { //TODO: This should be unnecessary
+ m_pool_key_to_index.erase(keypool.vchPubKey.GetID());
+ }
+ walletdb.ErasePool(index);
+ LogPrintf("keypool index %d removed\n", index);
+ it = setKeyPool->erase(it);
}
}
-void CWallet::GetScriptForMining(boost::shared_ptr<CReserveScript> &script)
+void CWallet::GetScriptForMining(std::shared_ptr<CReserveScript> &script)
{
- boost::shared_ptr<CReserveKey> rKey(new CReserveKey(this));
+ std::shared_ptr<CReserveKey> rKey = std::make_shared<CReserveKey>(this);
CPubKey pubkey;
if (!rKey->GetReservedKey(pubkey))
return;
@@ -3277,7 +3603,7 @@ bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const
return (setLockedCoins.count(outpt) > 0);
}
-void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts)
+void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts) const
{
AssertLockHeld(cs_wallet); // setLockedCoins
for (std::set<COutPoint>::iterator it = setLockedCoins.begin();
@@ -3289,57 +3615,24 @@ void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts)
/** @} */ // end of Actions
-class CAffectedKeysVisitor : public boost::static_visitor<void> {
-private:
- const CKeyStore &keystore;
- std::vector<CKeyID> &vKeys;
-
-public:
- CAffectedKeysVisitor(const CKeyStore &keystoreIn, std::vector<CKeyID> &vKeysIn) : keystore(keystoreIn), vKeys(vKeysIn) {}
-
- void Process(const CScript &script) {
- txnouttype type;
- std::vector<CTxDestination> vDest;
- int nRequired;
- if (ExtractDestinations(script, type, vDest, nRequired)) {
- BOOST_FOREACH(const CTxDestination &dest, vDest)
- boost::apply_visitor(*this, dest);
- }
- }
-
- void operator()(const CKeyID &keyId) {
- if (keystore.HaveKey(keyId))
- vKeys.push_back(keyId);
- }
-
- void operator()(const CScriptID &scriptId) {
- CScript script;
- if (keystore.GetCScript(scriptId, script))
- Process(script);
- }
-
- void operator()(const CNoDestination &none) {}
-};
-
-void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const {
+void CWallet::GetKeyBirthTimes(std::map<CTxDestination, int64_t> &mapKeyBirth) const {
AssertLockHeld(cs_wallet); // mapKeyMetadata
mapKeyBirth.clear();
// get birth times for keys with metadata
- for (std::map<CKeyID, CKeyMetadata>::const_iterator it = mapKeyMetadata.begin(); it != mapKeyMetadata.end(); it++)
- if (it->second.nCreateTime)
- mapKeyBirth[it->first] = it->second.nCreateTime;
+ for (const auto& entry : mapKeyMetadata) {
+ if (entry.second.nCreateTime) {
+ mapKeyBirth[entry.first] = entry.second.nCreateTime;
+ }
+ }
// map in which we'll infer heights of other keys
CBlockIndex *pindexMax = chainActive[std::max(0, chainActive.Height() - 144)]; // the tip can be reorganized; use a 144-block safety margin
std::map<CKeyID, CBlockIndex*> mapKeyFirstBlock;
- std::set<CKeyID> setKeys;
- GetKeys(setKeys);
- BOOST_FOREACH(const CKeyID &keyid, setKeys) {
+ for (const CKeyID &keyid : GetKeys()) {
if (mapKeyBirth.count(keyid) == 0)
mapKeyFirstBlock[keyid] = pindexMax;
}
- setKeys.clear();
// if there are no such keys, we're done
if (mapKeyFirstBlock.empty())
@@ -3354,10 +3647,10 @@ void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const {
if (blit != mapBlockIndex.end() && chainActive.Contains(blit->second)) {
// ... which are already in a block
int nHeight = blit->second->nHeight;
- BOOST_FOREACH(const CTxOut &txout, wtx.tx->vout) {
+ for (const CTxOut &txout : wtx.tx->vout) {
// iterate over all their outputs
CAffectedKeysVisitor(*this, vAffected).Process(txout.scriptPubKey);
- BOOST_FOREACH(const CKeyID &keyid, vAffected) {
+ for (const CKeyID &keyid : vAffected) {
// ... and all their affected keys
std::map<CKeyID, CBlockIndex*>::iterator rit = mapKeyFirstBlock.find(keyid);
if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->nHeight)
@@ -3370,7 +3663,72 @@ void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const {
// Extract block timestamps for those keys
for (std::map<CKeyID, CBlockIndex*>::const_iterator it = mapKeyFirstBlock.begin(); it != mapKeyFirstBlock.end(); it++)
- mapKeyBirth[it->first] = it->second->GetBlockTime() - 7200; // block times can be 2h off
+ mapKeyBirth[it->first] = it->second->GetBlockTime() - TIMESTAMP_WINDOW; // block times can be 2h off
+}
+
+/**
+ * Compute smart timestamp for a transaction being added to the wallet.
+ *
+ * Logic:
+ * - If sending a transaction, assign its timestamp to the current time.
+ * - If receiving a transaction outside a block, assign its timestamp to the
+ * current time.
+ * - If receiving a block with a future timestamp, assign all its (not already
+ * known) transactions' timestamps to the current time.
+ * - If receiving a block with a past timestamp, before the most recent known
+ * transaction (that we care about), assign all its (not already known)
+ * transactions' timestamps to the same timestamp as that most-recent-known
+ * transaction.
+ * - If receiving a block with a past timestamp, but after the most recent known
+ * transaction, assign all its (not already known) transactions' timestamps to
+ * the block time.
+ *
+ * For more information see CWalletTx::nTimeSmart,
+ * https://bitcointalk.org/?topic=54527, or
+ * https://github.com/bitcoin/bitcoin/pull/1393.
+ */
+unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const
+{
+ unsigned int nTimeSmart = wtx.nTimeReceived;
+ if (!wtx.hashUnset()) {
+ if (mapBlockIndex.count(wtx.hashBlock)) {
+ int64_t latestNow = wtx.nTimeReceived;
+ int64_t latestEntry = 0;
+
+ // Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future
+ int64_t latestTolerated = latestNow + 300;
+ const TxItems& txOrdered = wtxOrdered;
+ for (auto it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) {
+ CWalletTx* const pwtx = it->second.first;
+ if (pwtx == &wtx) {
+ continue;
+ }
+ CAccountingEntry* const pacentry = it->second.second;
+ int64_t nSmartTime;
+ if (pwtx) {
+ nSmartTime = pwtx->nTimeSmart;
+ if (!nSmartTime) {
+ nSmartTime = pwtx->nTimeReceived;
+ }
+ } else {
+ nSmartTime = pacentry->nTime;
+ }
+ if (nSmartTime <= latestTolerated) {
+ latestEntry = nSmartTime;
+ if (nSmartTime > latestNow) {
+ latestNow = nSmartTime;
+ }
+ break;
+ }
+ }
+
+ int64_t blocktime = mapBlockIndex[wtx.hashBlock]->GetBlockTime();
+ nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
+ } else {
+ LogPrintf("%s: found %s in block %s not in index\n", __func__, wtx.GetHash().ToString(), wtx.hashBlock.ToString());
+ }
+ }
+ return nTimeSmart;
}
bool CWallet::AddDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
@@ -3379,18 +3737,14 @@ bool CWallet::AddDestData(const CTxDestination &dest, const std::string &key, co
return false;
mapAddressBook[dest].destdata.insert(std::make_pair(key, value));
- if (!fFileBacked)
- return true;
- return CWalletDB(strWalletFile).WriteDestData(CBitcoinAddress(dest).ToString(), key, value);
+ return CWalletDB(*dbw).WriteDestData(EncodeDestination(dest), key, value);
}
bool CWallet::EraseDestData(const CTxDestination &dest, const std::string &key)
{
if (!mapAddressBook[dest].destdata.erase(key))
return false;
- if (!fFileBacked)
- return true;
- return CWalletDB(strWalletFile).EraseDestData(CBitcoinAddress(dest).ToString(), key);
+ return CWalletDB(*dbw).EraseDestData(EncodeDestination(dest), key);
}
bool CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
@@ -3415,43 +3769,18 @@ bool CWallet::GetDestData(const CTxDestination &dest, const std::string &key, st
return false;
}
-std::string CWallet::GetWalletHelpString(bool showDebug)
+std::vector<std::string> CWallet::GetDestValues(const std::string& prefix) const
{
- std::string 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)"), DEFAULT_KEYPOOL_SIZE));
- strUsage += HelpMessageOpt("-fallbackfee=<amt>", strprintf(_("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)"),
- CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)));
- strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)"),
- CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE)));
- 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 on startup"));
- if (showDebug)
- strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), DEFAULT_SEND_FREE_TRANSACTIONS));
- strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE));
- 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("-usehd", _("Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start") + " " + strprintf(_("(default: %u)"), DEFAULT_USE_HD_WALLET));
- strUsage += HelpMessageOpt("-walletrbf", strprintf(_("Send transactions with full-RBF opt-in enabled (default: %u)"), DEFAULT_WALLET_RBF));
- strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format on startup"));
- strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT));
- strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), DEFAULT_WALLETBROADCAST));
- 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)"));
-
- if (showDebug)
- {
- strUsage += HelpMessageGroup(_("Wallet debugging/testing options:"));
-
- strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf("Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE));
- strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET));
- strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB));
- strUsage += HelpMessageOpt("-walletrejectlongchains", strprintf(_("Wallet will not create transactions that violate mempool chain limits (default: %u)"), DEFAULT_WALLET_REJECT_LONG_CHAINS));
+ LOCK(cs_wallet);
+ std::vector<std::string> values;
+ for (const auto& address : mapAddressBook) {
+ for (const auto& data : address.second.destdata) {
+ if (!data.first.compare(0, prefix.size(), prefix)) {
+ values.emplace_back(data.second);
+ }
+ }
}
-
- return strUsage;
+ return values;
}
CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
@@ -3459,31 +3788,30 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
// needed to restore wallet transaction meta data after -zapwallettxes
std::vector<CWalletTx> vWtx;
- if (GetBoolArg("-zapwallettxes", false)) {
+ if (gArgs.GetBoolArg("-zapwallettxes", false)) {
uiInterface.InitMessage(_("Zapping all transactions from wallet..."));
- CWallet *tempWallet = new CWallet(walletFile);
+ std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, walletFile));
+ std::unique_ptr<CWallet> tempWallet(new CWallet(std::move(dbw)));
DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx);
if (nZapWalletRet != DB_LOAD_OK) {
InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile));
- return NULL;
+ return nullptr;
}
-
- delete tempWallet;
- tempWallet = NULL;
}
uiInterface.InitMessage(_("Loading wallet..."));
int64_t nStart = GetTimeMillis();
bool fFirstRun = true;
- CWallet *walletInstance = new CWallet(walletFile);
+ std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, walletFile));
+ CWallet *walletInstance = new CWallet(std::move(dbw));
DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun);
if (nLoadWalletRet != DB_LOAD_OK)
{
if (nLoadWalletRet == DB_CORRUPT) {
InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile));
- return NULL;
+ return nullptr;
}
else if (nLoadWalletRet == DB_NONCRITICAL_ERROR)
{
@@ -3493,22 +3821,22 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
}
else if (nLoadWalletRet == DB_TOO_NEW) {
InitError(strprintf(_("Error loading %s: Wallet requires newer version of %s"), walletFile, _(PACKAGE_NAME)));
- return NULL;
+ return nullptr;
}
else if (nLoadWalletRet == DB_NEED_REWRITE)
{
InitError(strprintf(_("Wallet needed to be rewritten: restart %s to complete"), _(PACKAGE_NAME)));
- return NULL;
+ return nullptr;
}
else {
InitError(strprintf(_("Error loading %s"), walletFile));
- return NULL;
+ return nullptr;
}
}
- if (GetBoolArg("-upgradewallet", fFirstRun))
+ if (gArgs.GetBoolArg("-upgradewallet", fFirstRun))
{
- int nMaxVersion = GetArg("-upgradewallet", 0);
+ int nMaxVersion = gArgs.GetArg("-upgradewallet", 0);
if (nMaxVersion == 0) // the -upgradewallet without argument case
{
LogPrintf("Performing wallet upgrade to %i\n", FEATURE_LATEST);
@@ -3520,40 +3848,42 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
if (nMaxVersion < walletInstance->GetVersion())
{
InitError(_("Cannot downgrade wallet"));
- return NULL;
+ return nullptr;
}
walletInstance->SetMaxVersion(nMaxVersion);
}
if (fFirstRun)
{
- // Create new keyUser and set as default key
- if (GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET) && !walletInstance->IsHDEnabled()) {
- // generate a new master key
- CPubKey masterPubKey = walletInstance->GenerateNewHDMasterKey();
- if (!walletInstance->SetHDMasterKey(masterPubKey))
- throw std::runtime_error(std::string(__func__) + ": Storing master key failed");
- }
- CPubKey newDefaultKey;
- if (walletInstance->GetKeyFromPool(newDefaultKey)) {
- walletInstance->SetDefaultKey(newDefaultKey);
- if (!walletInstance->SetAddressBook(walletInstance->vchDefaultKey.GetID(), "", "receive")) {
- InitError(_("Cannot write default address") += "\n");
- return NULL;
- }
+ // ensure this wallet.dat can only be opened by clients supporting HD with chain split and expects no default key
+ if (!gArgs.GetBoolArg("-usehd", true)) {
+ InitError(strprintf(_("Error creating %s: You can't create non-HD wallets with this version."), walletFile));
+ return nullptr;
+ }
+ walletInstance->SetMinVersion(FEATURE_NO_DEFAULT_KEY);
+
+ // generate a new master key
+ CPubKey masterPubKey = walletInstance->GenerateNewHDMasterKey();
+ if (!walletInstance->SetHDMasterKey(masterPubKey))
+ throw std::runtime_error(std::string(__func__) + ": Storing master key failed");
+
+ // Top up the keypool
+ if (!walletInstance->TopUpKeyPool()) {
+ InitError(_("Unable to generate initial keys") += "\n");
+ return NULL;
}
walletInstance->SetBestChain(chainActive.GetLocator());
}
- else if (IsArgSet("-usehd")) {
- bool useHD = GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET);
+ else if (gArgs.IsArgSet("-usehd")) {
+ bool useHD = gArgs.GetBoolArg("-usehd", true);
if (walletInstance->IsHDEnabled() && !useHD) {
- InitError(strprintf(_("Error loading %s: You can't disable HD on a already existing HD wallet"), walletFile));
- return NULL;
+ InitError(strprintf(_("Error loading %s: You can't disable HD on an already existing HD wallet"), walletFile));
+ return nullptr;
}
if (!walletInstance->IsHDEnabled() && useHD) {
- InitError(strprintf(_("Error loading %s: You can't enable HD on a already existing non-HD wallet"), walletFile));
- return NULL;
+ InitError(strprintf(_("Error loading %s: You can't enable HD on an already existing non-HD wallet"), walletFile));
+ return nullptr;
}
}
@@ -3561,22 +3891,21 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
RegisterValidationInterface(walletInstance);
- CBlockIndex *pindexRescan = chainActive.Tip();
- if (GetBoolArg("-rescan", false))
- pindexRescan = chainActive.Genesis();
- else
+ // Try to top up keypool. No-op if the wallet is locked.
+ walletInstance->TopUpKeyPool();
+
+ CBlockIndex *pindexRescan = chainActive.Genesis();
+ if (!gArgs.GetBoolArg("-rescan", false))
{
- CWalletDB walletdb(walletFile);
+ CWalletDB walletdb(*walletInstance->dbw);
CBlockLocator locator;
if (walletdb.ReadBestBlock(locator))
pindexRescan = FindForkInGlobalIndex(chainActive, locator);
- else
- pindexRescan = chainActive.Genesis();
}
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
+ //this might happen if a user uses an old wallet within a pruned node
// or if he ran -disablewallet for a longer time, then decided to re-enable
if (fPruneMode)
{
@@ -3586,24 +3915,31 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
if (pindexRescan != block) {
InitError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)"));
- return NULL;
+ return nullptr;
}
}
uiInterface.InitMessage(_("Rescanning..."));
LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight);
+
+ // No need to read and scan block if block was created before
+ // our wallet birthday (as adjusted for block time variability)
+ while (pindexRescan && walletInstance->nTimeFirstKey && (pindexRescan->GetBlockTime() < (walletInstance->nTimeFirstKey - TIMESTAMP_WINDOW))) {
+ pindexRescan = chainActive.Next(pindexRescan);
+ }
+
nStart = GetTimeMillis();
walletInstance->ScanForWalletTransactions(pindexRescan, true);
LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart);
walletInstance->SetBestChain(chainActive.GetLocator());
- nWalletDBUpdated++;
+ walletInstance->dbw->IncrementUpdateCounter();
// Restore wallet transaction metadata after -zapwallettxes=1
- if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2")
+ if (gArgs.GetBoolArg("-zapwallettxes", false) && gArgs.GetArg("-zapwallettxes", "1") != "2")
{
- CWalletDB walletdb(walletFile);
+ CWalletDB walletdb(*walletInstance->dbw);
- BOOST_FOREACH(const CWalletTx& wtxOld, vWtx)
+ for (const CWalletTx& wtxOld : vWtx)
{
uint256 hash = wtxOld.GetHash();
std::map<uint256, CWalletTx>::iterator mi = walletInstance->mapWallet.find(hash);
@@ -3623,7 +3959,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
}
}
}
- walletInstance->SetBroadcastTransactions(GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST));
+ walletInstance->SetBroadcastTransactions(gArgs.GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST));
{
LOCK(walletInstance->cs_wallet);
@@ -3635,177 +3971,36 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
return walletInstance;
}
-bool CWallet::InitLoadWallet()
-{
- if (GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
- pwalletMain = NULL;
- LogPrintf("Wallet disabled!\n");
- return true;
- }
+std::atomic<bool> CWallet::fFlushScheduled(false);
- std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT);
-
- CWallet * const pwallet = CreateWalletFromFile(walletFile);
- if (!pwallet) {
- return false;
- }
- pwalletMain = pwallet;
-
- return true;
-}
-
-std::atomic<bool> CWallet::fFlushThreadRunning(false);
-
-void CWallet::postInitProcess(boost::thread_group& threadGroup)
+void CWallet::postInitProcess(CScheduler& scheduler)
{
// Add wallet transactions that aren't already in a block to mempool
// Do this here as mempool requires genesis block to be loaded
ReacceptWalletTransactions();
// Run a thread to flush wallet periodically
- if (!CWallet::fFlushThreadRunning.exchange(true)) {
- threadGroup.create_thread(ThreadFlushWalletDB);
+ if (!CWallet::fFlushScheduled.exchange(true)) {
+ scheduler.scheduleEvery(MaybeCompactWalletDB, 500);
}
}
-bool CWallet::ParameterInteraction()
-{
- if (GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET))
- return true;
-
- if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && SoftSetBoolArg("-walletbroadcast", false)) {
- LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__);
- }
-
- if (GetBoolArg("-salvagewallet", false) && SoftSetBoolArg("-rescan", true)) {
- // Rewrite just private keys: rescan to find transactions
- LogPrintf("%s: parameter interaction: -salvagewallet=1 -> setting -rescan=1\n", __func__);
- }
-
- // -zapwallettx implies a rescan
- if (GetBoolArg("-zapwallettxes", false) && SoftSetBoolArg("-rescan", true)) {
- LogPrintf("%s: parameter interaction: -zapwallettxes=<mode> -> setting -rescan=1\n", __func__);
- }
-
- if (GetBoolArg("-sysperms", false))
- return InitError("-sysperms is not allowed in combination with enabled wallet functionality");
- if (GetArg("-prune", 0) && 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."));
-
- if (::minRelayTxFee.GetFeePerK() > HIGH_TX_FEE_PER_KB)
- InitWarning(AmountHighWarn("-minrelaytxfee") + " " +
- _("The wallet will avoid paying less than the minimum relay fee."));
-
- if (IsArgSet("-mintxfee"))
- {
- CAmount n = 0;
- if (!ParseMoney(GetArg("-mintxfee", ""), n) || 0 == n)
- return InitError(AmountErrMsg("mintxfee", GetArg("-mintxfee", "")));
- if (n > HIGH_TX_FEE_PER_KB)
- InitWarning(AmountHighWarn("-mintxfee") + " " +
- _("This is the minimum transaction fee you pay on every transaction."));
- CWallet::minTxFee = CFeeRate(n);
- }
- if (IsArgSet("-fallbackfee"))
- {
- CAmount nFeePerK = 0;
- if (!ParseMoney(GetArg("-fallbackfee", ""), nFeePerK))
- return InitError(strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), GetArg("-fallbackfee", "")));
- if (nFeePerK > HIGH_TX_FEE_PER_KB)
- InitWarning(AmountHighWarn("-fallbackfee") + " " +
- _("This is the transaction fee you may pay when fee estimates are not available."));
- CWallet::fallbackFee = CFeeRate(nFeePerK);
- }
- if (IsArgSet("-paytxfee"))
- {
- CAmount nFeePerK = 0;
- if (!ParseMoney(GetArg("-paytxfee", ""), nFeePerK))
- return InitError(AmountErrMsg("paytxfee", GetArg("-paytxfee", "")));
- if (nFeePerK > HIGH_TX_FEE_PER_KB)
- InitWarning(AmountHighWarn("-paytxfee") + " " +
- _("This is the transaction fee you will pay if you send a transaction."));
-
- payTxFee = CFeeRate(nFeePerK, 1000);
- if (payTxFee < ::minRelayTxFee)
- {
- return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
- GetArg("-paytxfee", ""), ::minRelayTxFee.ToString()));
- }
- }
- if (IsArgSet("-maxtxfee"))
- {
- CAmount nMaxFee = 0;
- if (!ParseMoney(GetArg("-maxtxfee", ""), nMaxFee))
- return InitError(AmountErrMsg("maxtxfee", GetArg("-maxtxfee", "")));
- if (nMaxFee > HIGH_MAX_TX_FEE)
- InitWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
- maxTxFee = nMaxFee;
- if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee)
- {
- return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
- GetArg("-maxtxfee", ""), ::minRelayTxFee.ToString()));
- }
- }
- nTxConfirmTarget = GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);
- bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
- fSendFreeTransactions = GetBoolArg("-sendfreetransactions", DEFAULT_SEND_FREE_TRANSACTIONS);
- fWalletRbf = GetBoolArg("-walletrbf", DEFAULT_WALLET_RBF);
-
- if (fSendFreeTransactions && GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) <= 0)
- return InitError("Creation of free transactions with their relay disabled is not supported.");
-
- return true;
-}
-
bool CWallet::BackupWallet(const std::string& strDest)
{
- if (!fFileBacked)
- return false;
- while (true)
- {
- {
- LOCK(bitdb.cs_db);
- if (!bitdb.mapFileUseCount.count(strWalletFile) || bitdb.mapFileUseCount[strWalletFile] == 0)
- {
- // Flush log data to the dat file
- bitdb.CloseDb(strWalletFile);
- bitdb.CheckpointLSN(strWalletFile);
- bitdb.mapFileUseCount.erase(strWalletFile);
-
- // Copy wallet file
- boost::filesystem::path pathSrc = GetDataDir() / strWalletFile;
- boost::filesystem::path pathDest(strDest);
- if (boost::filesystem::is_directory(pathDest))
- pathDest /= strWalletFile;
-
- try {
-#if BOOST_VERSION >= 104000
- boost::filesystem::copy_file(pathSrc, pathDest, boost::filesystem::copy_option::overwrite_if_exists);
-#else
- boost::filesystem::copy_file(pathSrc, pathDest);
-#endif
- LogPrintf("copied %s to %s\n", strWalletFile, pathDest.string());
- return true;
- } catch (const boost::filesystem::filesystem_error& e) {
- LogPrintf("error copying %s to %s - %s\n", strWalletFile, pathDest.string(), e.what());
- return false;
- }
- }
- }
- MilliSleep(100);
- }
- return false;
+ return dbw->Backup(strDest);
}
CKeyPool::CKeyPool()
{
nTime = GetTime();
+ fInternal = false;
}
-CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn)
+CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn)
{
nTime = GetTime();
vchPubKey = vchPubKeyIn;
+ fInternal = internalIn;
}
CWalletKey::CWalletKey(int64_t nExpires)
@@ -3846,11 +4041,12 @@ int CMerkleTx::GetBlocksToMaturity() const
{
if (!IsCoinBase())
return 0;
- return max(0, (COINBASE_MATURITY+1) - GetDepthInMainChain());
+ return std::max(0, (COINBASE_MATURITY+1) - GetDepthInMainChain());
}
bool CMerkleTx::AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state)
{
- return ::AcceptToMemoryPool(mempool, state, tx, true, NULL, false, nAbsurdFee);
+ return ::AcceptToMemoryPool(mempool, state, tx, nullptr /* pfMissingInputs */,
+ nullptr /* plTxnReplaced */, false /* bypass_limits */, nAbsurdFee);
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 92ad098486..c4af192f36 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -7,12 +7,14 @@
#define BITCOIN_WALLET_WALLET_H
#include "amount.h"
+#include "policy/feerate.h"
#include "streams.h"
#include "tinyformat.h"
#include "ui_interface.h"
#include "utilstrencodings.h"
#include "validationinterface.h"
#include "script/ismine.h"
+#include "script/sign.h"
#include "wallet/crypter.h"
#include "wallet/walletdb.h"
#include "wallet/rpcwallet.h"
@@ -27,10 +29,8 @@
#include <utility>
#include <vector>
-#include <boost/shared_ptr.hpp>
-#include <boost/thread.hpp>
-
-extern CWallet* pwalletMain;
+typedef CWallet* CWalletRef;
+extern std::vector<CWalletRef> vpwallets;
/**
* Settings
@@ -38,56 +38,64 @@ extern CWallet* pwalletMain;
extern CFeeRate payTxFee;
extern unsigned int nTxConfirmTarget;
extern bool bSpendZeroConfChange;
-extern bool fSendFreeTransactions;
extern bool fWalletRbf;
-static const unsigned int DEFAULT_KEYPOOL_SIZE = 100;
+static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000;
//! -paytxfee default
static const CAmount DEFAULT_TRANSACTION_FEE = 0;
//! -fallbackfee default
static const CAmount DEFAULT_FALLBACK_FEE = 20000;
+//! -m_discard_rate default
+static const CAmount DEFAULT_DISCARD_FEE = 10000;
//! -mintxfee default
static const CAmount DEFAULT_TRANSACTION_MINFEE = 1000;
+//! minimum recommended increment for BIP 125 replacement txs
+static const CAmount WALLET_INCREMENTAL_RELAY_FEE = 5000;
//! target minimum change amount
static const CAmount MIN_CHANGE = CENT;
//! final minimum change amount after paying for fees
static const CAmount MIN_FINAL_CHANGE = MIN_CHANGE/2;
//! Default for -spendzeroconfchange
static const bool DEFAULT_SPEND_ZEROCONF_CHANGE = true;
-//! Default for -sendfreetransactions
-static const bool DEFAULT_SEND_FREE_TRANSACTIONS = false;
//! Default for -walletrejectlongchains
static const bool DEFAULT_WALLET_REJECT_LONG_CHAINS = false;
//! -txconfirmtarget default
static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 6;
//! -walletrbf default
static const bool DEFAULT_WALLET_RBF = false;
-//! Largest (in bytes) free transaction we're willing to create
-static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000;
static const bool DEFAULT_WALLETBROADCAST = true;
static const bool DEFAULT_DISABLE_WALLET = false;
-//! if set, all keys will be derived by using BIP32
-static const bool DEFAULT_USE_HD_WALLET = true;
extern const char * DEFAULT_WALLET_DAT;
+static const int64_t TIMESTAMP_MIN = 0;
+
class CBlockIndex;
class CCoinControl;
class COutput;
class CReserveKey;
class CScript;
+class CScheduler;
class CTxMemPool;
+class CBlockPolicyEstimator;
class CWalletTx;
+struct FeeCalculation;
+enum class FeeEstimateMode;
/** (client) version numbers for particular wallet features */
enum WalletFeature
{
- FEATURE_BASE = 10500, // the earliest version new wallets supports (only useful for getinfo's clientversion output)
+ FEATURE_BASE = 10500, // the earliest version new wallets supports (only useful for getwalletinfo's clientversion output)
FEATURE_WALLETCRYPT = 40000, // wallet encryption
FEATURE_COMPRPUBKEY = 60000, // compressed public keys
FEATURE_HD = 130000, // Hierarchical key derivation after BIP32 (HD Wallet)
+
+ FEATURE_HD_SPLIT = 139900, // Wallet with HD chain split (change outputs will use m/0'/1'/k)
+
+ FEATURE_NO_DEFAULT_KEY = 159900, // Wallet without a default key written
+
FEATURE_LATEST = FEATURE_COMPRPUBKEY // HD is optional, use FEATURE_COMPRPUBKEY as latest version
};
@@ -98,9 +106,10 @@ class CKeyPool
public:
int64_t nTime;
CPubKey vchPubKey;
+ bool fInternal; // for change outputs
CKeyPool();
- CKeyPool(const CPubKey& vchPubKeyIn);
+ CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn);
ADD_SERIALIZE_METHODS;
@@ -111,6 +120,19 @@ public:
READWRITE(nVersion);
READWRITE(nTime);
READWRITE(vchPubKey);
+ if (ser_action.ForRead()) {
+ try {
+ READWRITE(fInternal);
+ }
+ catch (std::ios_base::failure&) {
+ /* flag as external address if we can't read the internal boolean
+ (this will be the case for any wallet before the HD chain split version) */
+ fInternal = false;
+ }
+ }
+ else {
+ READWRITE(fInternal);
+ }
}
};
@@ -121,10 +143,7 @@ public:
std::string name;
std::string purpose;
- CAddressBookData()
- {
- purpose = "unknown";
- }
+ CAddressBookData() : purpose("unknown") {}
typedef std::map<std::string, std::string> StringMap;
StringMap destdata;
@@ -189,7 +208,7 @@ public:
Init();
}
- CMerkleTx(CTransactionRef arg)
+ explicit CMerkleTx(CTransactionRef arg)
{
SetTx(std::move(arg));
Init();
@@ -253,11 +272,50 @@ private:
const CWallet* pwallet;
public:
+ /**
+ * Key/value map with information about the transaction.
+ *
+ * The following keys can be read and written through the map and are
+ * serialized in the wallet database:
+ *
+ * "comment", "to" - comment strings provided to sendtoaddress,
+ * sendfrom, sendmany wallet RPCs
+ * "replaces_txid" - txid (as HexStr) of transaction replaced by
+ * bumpfee on transaction created by bumpfee
+ * "replaced_by_txid" - txid (as HexStr) of transaction created by
+ * bumpfee on transaction replaced by bumpfee
+ * "from", "message" - obsolete fields that could be set in UI prior to
+ * 2011 (removed in commit 4d9b223)
+ *
+ * The following keys are serialized in the wallet database, but shouldn't
+ * be read or written through the map (they will be temporarily added and
+ * removed from the map during serialization):
+ *
+ * "fromaccount" - serialized strFromAccount value
+ * "n" - serialized nOrderPos value
+ * "timesmart" - serialized nTimeSmart value
+ * "spent" - serialized vfSpent value that existed prior to
+ * 2014 (removed in commit 93a18a3)
+ */
mapValue_t mapValue;
std::vector<std::pair<std::string, std::string> > vOrderForm;
unsigned int fTimeReceivedIsTxTime;
unsigned int nTimeReceived; //!< time received by this node
+ /**
+ * Stable timestamp that never changes, and reflects the order a transaction
+ * was added to the wallet. Timestamp is based on the block time for a
+ * transaction added as part of a block, or else the time when the
+ * transaction was received if it wasn't part of a block, with the timestamp
+ * adjusted in both cases so timestamp order matches the order transactions
+ * were added to the wallet. More details can be found in
+ * CWallet::ComputeTimeSmart().
+ */
unsigned int nTimeSmart;
+ /**
+ * From me flag is set to 1 for transactions that were created by the wallet
+ * on this bitcoin node, and set to 0 for transactions that were created
+ * externally and came in through the network or sendrawtransaction RPC.
+ */
char fFromMe;
std::string strFromAccount;
int64_t nOrderPos; //!< position in ordered transaction list
@@ -284,7 +342,7 @@ public:
CWalletTx()
{
- Init(NULL);
+ Init(nullptr);
}
CWalletTx(const CWallet* pwalletIn, CTransactionRef arg) : CMerkleTx(std::move(arg))
@@ -328,7 +386,7 @@ public:
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
if (ser_action.ForRead())
- Init(NULL);
+ Init(nullptr);
char fSpent = false;
if (!ser_action.ForRead())
@@ -361,7 +419,6 @@ public:
}
mapValue.erase("fromaccount");
- mapValue.erase("version");
mapValue.erase("spent");
mapValue.erase("n");
mapValue.erase("timesmart");
@@ -399,9 +456,6 @@ public:
void GetAmounts(std::list<COutputEntry>& listReceived,
std::list<COutputEntry>& listSent, CAmount& nFee, std::string& strSentAccount, const isminefilter& filter) const;
- void GetAccountAmounts(const std::string& strAccount, CAmount& nReceived,
- CAmount& nSent, CAmount& nFee, const isminefilter& filter) const;
-
bool IsFromMe(const isminefilter& filter) const
{
return (GetDebit(filter) > 0);
@@ -416,13 +470,41 @@ public:
int64_t GetTxTime() const;
int GetRequestCount() const;
+ // RelayWalletTransaction may only be called if fBroadcastTransactions!
bool RelayWalletTransaction(CConnman* connman);
std::set<uint256> GetConflicts() const;
};
+class CInputCoin {
+public:
+ CInputCoin(const CWalletTx* walletTx, unsigned int i)
+ {
+ if (!walletTx)
+ throw std::invalid_argument("walletTx should not be null");
+ if (i >= walletTx->tx->vout.size())
+ throw std::out_of_range("The output index is out of range");
+
+ outpoint = COutPoint(walletTx->GetHash(), i);
+ txout = walletTx->tx->vout[i];
+ }
+ COutPoint outpoint;
+ CTxOut txout;
+
+ bool operator<(const CInputCoin& rhs) const {
+ return outpoint < rhs.outpoint;
+ }
+
+ bool operator!=(const CInputCoin& rhs) const {
+ return outpoint != rhs.outpoint;
+ }
+
+ bool operator==(const CInputCoin& rhs) const {
+ return outpoint == rhs.outpoint;
+ }
+};
class COutput
{
@@ -430,12 +512,23 @@ public:
const CWalletTx *tx;
int i;
int nDepth;
+
+ /** Whether we have the private keys to spend this output */
bool fSpendable;
+
+ /** Whether we know how to spend this output, ignoring the lack of keys */
bool fSolvable;
- COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn, bool fSolvableIn)
+ /**
+ * Whether this output is considered safe to spend. Unconfirmed transactions
+ * from outside keys and unconfirmed replacement transactions are considered
+ * unsafe and will not be used to fund new spending transactions.
+ */
+ bool fSafe;
+
+ COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn, bool fSolvableIn, bool fSafeIn)
{
- tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn; fSolvable = fSolvableIn;
+ tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn; fSolvable = fSolvableIn; fSafe = fSafeIn;
}
std::string ToString() const;
@@ -455,7 +548,7 @@ public:
//! todo: add something to note what created it (user, getnewaddress, change)
//! maybe should have a map<string, string> property map
- CWalletKey(int64_t nExpires=0);
+ explicit CWalletKey(int64_t nExpires=0);
ADD_SERIALIZE_METHODS;
@@ -558,17 +651,19 @@ private:
* A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,
* and provides the ability to create new transactions.
*/
-class CWallet : public CCryptoKeyStore, public CValidationInterface
+class CWallet final : public CCryptoKeyStore, public CValidationInterface
{
private:
- static std::atomic<bool> fFlushThreadRunning;
+ static std::atomic<bool> fFlushScheduled;
+ std::atomic<bool> fAbortRescan;
+ std::atomic<bool> fScanningWallet;
/**
* Select a set of coins such that nValueRet >= nTargetValue and at least
* all coins from coinControl are selected; Never select unconfirmed coins
* if they are not ours
*/
- bool SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl *coinControl = NULL) const;
+ bool SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CCoinControl *coinControl = nullptr) const;
CWalletDB *pwalletdbEncryption;
@@ -597,71 +692,106 @@ private:
void SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator>);
+ /* Used by TransactionAddedToMemorypool/BlockConnected/Disconnected.
+ * Should be called with pindexBlock and posInBlock if this is for a transaction that is included in a block. */
+ void SyncTransaction(const CTransactionRef& tx, const CBlockIndex *pindex = nullptr, int posInBlock = 0);
+
/* the HD chain data model (external chain counters) */
CHDChain hdChain;
- bool fFileBacked;
+ /* HD derive new child key (on internal or external chain) */
+ void DeriveNewChildKey(CWalletDB &walletdb, CKeyMetadata& metadata, CKey& secret, bool internal = false);
+
+ std::set<int64_t> setInternalKeyPool;
+ std::set<int64_t> setExternalKeyPool;
+ int64_t m_max_keypool_index;
+ std::map<CKeyID, int64_t> m_pool_key_to_index;
+
+ int64_t nTimeFirstKey;
+
+ /**
+ * Private version of AddWatchOnly method which does not accept a
+ * timestamp, and which will reset the wallet's nTimeFirstKey value to 1 if
+ * the watch key did not previously have a timestamp associated with it.
+ * Because this is an inherited virtual method, it is accessible despite
+ * being marked private, but it is marked private anyway to encourage use
+ * of the other AddWatchOnly which accepts a timestamp and sets
+ * nTimeFirstKey more intelligently for more efficient rescans.
+ */
+ bool AddWatchOnly(const CScript& dest) override;
+
+ std::unique_ptr<CWalletDBWrapper> dbw;
- std::set<int64_t> setKeyPool;
public:
/*
* Main wallet lock.
- * This lock protects all the fields added by CWallet
- * except for:
- * fFileBacked (immutable after instantiation)
- * strWalletFile (immutable after instantiation)
+ * This lock protects all the fields added by CWallet.
*/
mutable CCriticalSection cs_wallet;
- const std::string strWalletFile;
-
- void LoadKeyPool(int nIndex, const CKeyPool &keypool)
+ /** Get database handle used by this wallet. Ideally this function would
+ * not be necessary.
+ */
+ CWalletDBWrapper& GetDBHandle()
{
- setKeyPool.insert(nIndex);
+ return *dbw;
+ }
- // If no metadata exists yet, create a default with the pool key's
- // creation time. Note that this may be overwritten by actually
- // stored metadata for that key later, which is fine.
- CKeyID keyid = keypool.vchPubKey.GetID();
- if (mapKeyMetadata.count(keyid) == 0)
- mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime);
+ /** Get a name for this wallet for logging/debugging purposes.
+ */
+ std::string GetName() const
+ {
+ if (dbw) {
+ return dbw->GetName();
+ } else {
+ return "dummy";
+ }
}
- std::map<CKeyID, CKeyMetadata> mapKeyMetadata;
+ void LoadKeyPool(int64_t nIndex, const CKeyPool &keypool);
+
+ // Map from Key ID (for regular keys) or Script ID (for watch-only keys) to
+ // key metadata.
+ std::map<CTxDestination, CKeyMetadata> mapKeyMetadata;
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
MasterKeyMap mapMasterKeys;
unsigned int nMasterKeyMaxID;
- CWallet()
+ // Create wallet with dummy database handle
+ CWallet(): dbw(new CWalletDBWrapper())
{
SetNull();
}
- CWallet(const std::string& strWalletFileIn) : strWalletFile(strWalletFileIn)
+ // Create wallet with passed-in database handle
+ explicit CWallet(std::unique_ptr<CWalletDBWrapper> dbw_in) : dbw(std::move(dbw_in))
{
SetNull();
- fFileBacked = true;
}
~CWallet()
{
delete pwalletdbEncryption;
- pwalletdbEncryption = NULL;
+ pwalletdbEncryption = nullptr;
}
void SetNull()
{
nWalletVersion = FEATURE_BASE;
nWalletMaxVersion = FEATURE_BASE;
- fFileBacked = false;
nMasterKeyMaxID = 0;
- pwalletdbEncryption = NULL;
+ pwalletdbEncryption = nullptr;
nOrderPosNext = 0;
+ nAccountingEntryNumber = 0;
nNextResend = 0;
nLastResend = 0;
+ m_max_keypool_index = 0;
nTimeFirstKey = 0;
fBroadcastTransactions = false;
+ nRelockTime = 0;
+ fAbortRescan = false;
+ fScanningWallet = false;
}
std::map<uint256, CWalletTx> mapWallet;
@@ -672,25 +802,32 @@ public:
TxItems wtxOrdered;
int64_t nOrderPosNext;
+ uint64_t nAccountingEntryNumber;
std::map<uint256, int> mapRequestCount;
std::map<CTxDestination, CAddressBookData> mapAddressBook;
- CPubKey vchDefaultKey;
-
std::set<COutPoint> setLockedCoins;
- int64_t nTimeFirstKey;
-
const CWalletTx* GetWalletTx(const uint256& hash) const;
//! check whether we are allowed to upgrade (or already support) to the named feature
- bool CanSupportFeature(enum WalletFeature wf) { AssertLockHeld(cs_wallet); return nWalletMaxVersion >= wf; }
+ bool CanSupportFeature(enum WalletFeature wf) const { AssertLockHeld(cs_wallet); return nWalletMaxVersion >= wf; }
/**
* populate vCoins with vector of available COutputs.
*/
- void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL, bool fIncludeZeroValue=false) const;
+ void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlySafe=true, const CCoinControl *coinControl = nullptr, const CAmount& nMinimumAmount = 1, const CAmount& nMaximumAmount = MAX_MONEY, const CAmount& nMinimumSumAmount = MAX_MONEY, const uint64_t& nMaximumCount = 0, const int& nMinDepth = 0, const int& nMaxDepth = 9999999) const;
+
+ /**
+ * Return list of available coins and locked coins grouped by non-change output address.
+ */
+ std::map<CTxDestination, std::vector<COutput>> ListCoins() const;
+
+ /**
+ * Find non-change parent output.
+ */
+ const CTxOut& FindNonChangeParentOutput(const CTransaction& tx, int output) const;
/**
* Shuffle and select coins until nTargetValue is reached while avoiding
@@ -698,7 +835,7 @@ public:
* completion the coin set and corresponding actual target value is
* assembled
*/
- bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, uint64_t nMaxAncestors, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet) const;
+ bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, uint64_t nMaxAncestors, std::vector<COutput> vCoins, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet) const;
bool IsSpent(const uint256& hash, unsigned int n) const;
@@ -706,28 +843,36 @@ public:
void LockCoin(const COutPoint& output);
void UnlockCoin(const COutPoint& output);
void UnlockAllCoins();
- void ListLockedCoins(std::vector<COutPoint>& vOutpts);
+ void ListLockedCoins(std::vector<COutPoint>& vOutpts) const;
+
+ /*
+ * Rescan abort properties
+ */
+ void AbortRescan() { fAbortRescan = true; }
+ bool IsAbortingRescan() { return fAbortRescan; }
+ bool IsScanning() { return fScanningWallet; }
/**
* keystore implementation
* Generate a new key
*/
- CPubKey GenerateNewKey();
- void DeriveNewChildKey(CKeyMetadata& metadata, CKey& secret);
+ CPubKey GenerateNewKey(CWalletDB& walletdb, bool internal = false);
//! Adds a key to the store, and saves it to disk.
- bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
+ bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override;
+ bool AddKeyPubKeyWithDB(CWalletDB &walletdb,const CKey& key, const CPubKey &pubkey);
//! Adds a key to the store, without saving it to disk (used by LoadWallet)
bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); }
//! Load metadata (used by LoadWallet)
- bool LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &metadata);
+ bool LoadKeyMetadata(const CTxDestination& pubKey, const CKeyMetadata &metadata);
bool LoadMinVersion(int nVersion) { AssertLockHeld(cs_wallet); nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; }
+ void UpdateTimeFirstKey(int64_t nCreateTime);
//! Adds an encrypted key to the store, and saves it to disk.
- bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
+ bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) override;
//! Adds an encrypted key to the store, without saving it to disk (used by LoadWallet)
bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
- bool AddCScript(const CScript& redeemScript);
+ bool AddCScript(const CScript& redeemScript) override;
bool LoadCScript(const CScript& redeemScript);
//! Adds a destination data tuple to the store, and saves it to disk
@@ -738,24 +883,30 @@ public:
bool LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value);
//! Look up a destination data tuple in the store, return true if found false otherwise
bool GetDestData(const CTxDestination &dest, const std::string &key, std::string *value) const;
+ //! Get all destination values matching a prefix.
+ std::vector<std::string> GetDestValues(const std::string& prefix) const;
//! Adds a watch-only address to the store, and saves it to disk.
- bool AddWatchOnly(const CScript &dest);
- bool RemoveWatchOnly(const CScript &dest);
+ bool AddWatchOnly(const CScript& dest, int64_t nCreateTime);
+ bool RemoveWatchOnly(const CScript &dest) override;
//! Adds a watch-only address to the store, without saving it to disk (used by LoadWallet)
bool LoadWatchOnly(const CScript &dest);
+ //! Holds a timestamp at which point the wallet is scheduled (externally) to be relocked. Caller must arrange for actual relocking to occur via Lock().
+ int64_t nRelockTime;
+
bool Unlock(const SecureString& strWalletPassphrase);
bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
bool EncryptWallet(const SecureString& strWalletPassphrase);
- void GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const;
+ void GetKeyBirthTimes(std::map<CTxDestination, int64_t> &mapKeyBirth) const;
+ unsigned int ComputeTimeSmart(const CWalletTx& wtx) const;
/**
* Increment the next transaction order id
* @return next transaction order id
*/
- int64_t IncOrderPosNext(CWalletDB *pwalletdb = NULL);
+ int64_t IncOrderPosNext(CWalletDB *pwalletdb = nullptr);
DBErrors ReorderTransactions();
bool AccountMove(std::string strFrom, std::string strTo, CAmount nAmount, std::string strComment = "");
bool GetAccountPubkey(CPubKey &pubKey, std::string strAccount, bool bForceNew = false);
@@ -763,11 +914,15 @@ public:
void MarkDirty();
bool AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose=true);
bool LoadToWallet(const CWalletTx& wtxIn);
- void SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, int posInBlock);
- bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate);
- int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
+ void TransactionAddedToMempool(const CTransactionRef& tx) override;
+ void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) override;
+ void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) override;
+ bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate);
+ int64_t RescanFromTime(int64_t startTime, bool update);
+ CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
void ReacceptWalletTransactions();
- void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman);
+ void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override;
+ // ResendWalletTransactionsBefore may only be called if fBroadcastTransactions!
std::vector<uint256> ResendWalletTransactionsBefore(int64_t nTime, CConnman* connman);
CAmount GetBalance() const;
CAmount GetUnconfirmedBalance() const;
@@ -775,12 +930,15 @@ public:
CAmount GetWatchOnlyBalance() const;
CAmount GetUnconfirmedWatchOnlyBalance() const;
CAmount GetImmatureWatchOnlyBalance() const;
+ CAmount GetLegacyBalance(const isminefilter& filter, int minDepth, const std::string* account) const;
+ CAmount GetAvailableBalance(const CCoinControl* coinControl = nullptr) const;
/**
* Insert additional inputs into the transaction by
* calling CreateTransaction();
*/
- bool FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool overrideEstimatedFeeRate, const CFeeRate& specificFeeRate, int& nChangePosInOut, std::string& strFailReason, bool includeWatching, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, const CTxDestination& destChange = CNoDestination());
+ bool FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, CCoinControl);
+ bool SignTransaction(CMutableTransaction& tx);
/**
* Create a new transaction paying the recipients with a set of coins
@@ -788,43 +946,43 @@ public:
* @note passing nChangePosInOut as -1 will result in setting a random position
*/
bool CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosInOut,
- std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true);
+ std::string& strFailReason, const CCoinControl& coin_control, bool sign = true);
bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman, CValidationState& state);
void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries);
bool AddAccountingEntry(const CAccountingEntry&);
bool AddAccountingEntry(const CAccountingEntry&, CWalletDB *pwalletdb);
+ template <typename ContainerType>
+ bool DummySignTx(CMutableTransaction &txNew, const ContainerType &coins) const;
static CFeeRate minTxFee;
static CFeeRate fallbackFee;
- /**
- * Estimate the minimum fee considering user set parameters
- * and the required fee
- */
- static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool);
- /**
- * Return the minimum required fee taking into account the
- * floating relay fee and user set minimum transaction fee
- */
- static CAmount GetRequiredFee(unsigned int nTxBytes);
+ static CFeeRate m_discard_rate;
bool NewKeyPool();
+ size_t KeypoolCountExternalKeys();
bool TopUpKeyPool(unsigned int kpSize = 0);
- void ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool);
+ void ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRequestedInternal);
void KeepKey(int64_t nIndex);
- void ReturnKey(int64_t nIndex);
- bool GetKeyFromPool(CPubKey &key);
+ void ReturnKey(int64_t nIndex, bool fInternal, const CPubKey& pubkey);
+ bool GetKeyFromPool(CPubKey &key, bool internal = false);
int64_t GetOldestKeyPoolTime();
- void GetAllReserveKeys(std::set<CKeyID>& setAddress) const;
+ /**
+ * Marks all keys in the keypool up to and including reserve_key as used.
+ */
+ void MarkReserveKeysAsUsed(int64_t keypool_id);
+ const std::map<CKeyID, int64_t>& GetAllReserveKeys() const { return m_pool_key_to_index; }
std::set< std::set<CTxDestination> > GetAddressGroupings();
std::map<CTxDestination, CAmount> GetAddressBalances();
- CAmount GetAccountBalance(const std::string& strAccount, int nMinDepth, const isminefilter& filter);
- CAmount GetAccountBalance(CWalletDB& walletdb, const std::string& strAccount, int nMinDepth, const isminefilter& filter);
std::set<CTxDestination> GetAccountAddresses(const std::string& strAccount) const;
isminetype IsMine(const CTxIn& txin) const;
+ /**
+ * Returns amount of debit if the input matches the
+ * filter, otherwise returns 0
+ */
CAmount GetDebit(const CTxIn& txin, const isminefilter& filter) const;
isminetype IsMine(const CTxOut& txout) const;
CAmount GetCredit(const CTxOut& txout, const isminefilter& filter) const;
@@ -834,9 +992,11 @@ public:
/** should probably be renamed to IsRelevantToMe */
bool IsFromMe(const CTransaction& tx) const;
CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const;
+ /** Returns whether all of the inputs match the filter */
+ bool IsAllFromMe(const CTransaction& tx, const isminefilter& filter) const;
CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const;
CAmount GetChange(const CTransaction& tx) const;
- void SetBestChain(const CBlockLocator& loc);
+ void SetBestChain(const CBlockLocator& loc) override;
DBErrors LoadWallet(bool& fFirstRunRet);
DBErrors ZapWalletTx(std::vector<CWalletTx>& vWtx);
@@ -846,9 +1006,9 @@ public:
bool DelAddressBook(const CTxDestination& address);
- void UpdatedTransaction(const uint256 &hashTx);
+ const std::string& GetAccountName(const CScript& scriptPubKey) const;
- void Inventory(const uint256 &hash)
+ void Inventory(const uint256 &hash) override
{
{
LOCK(cs_wallet);
@@ -858,23 +1018,16 @@ public:
}
}
- void GetScriptForMining(boost::shared_ptr<CReserveScript> &script);
- void ResetRequestCount(const uint256 &hash)
- {
- LOCK(cs_wallet);
- mapRequestCount[hash] = 0;
- };
+ void GetScriptForMining(std::shared_ptr<CReserveScript> &script);
unsigned int GetKeyPoolSize()
{
- AssertLockHeld(cs_wallet); // setKeyPool
- return setKeyPool.size();
+ AssertLockHeld(cs_wallet); // set{Ex,In}ternalKeyPool
+ return setInternalKeyPool.size() + setExternalKeyPool.size();
}
- bool SetDefaultKey(const CPubKey &vchPubKey);
-
//! signify that a particular wallet feature is now used. this may change nWalletVersion and nWalletMaxVersion if those are lower
- bool SetMinVersion(enum WalletFeature, CWalletDB* pwalletdbIn = NULL, bool fExplicit = false);
+ bool SetMinVersion(enum WalletFeature, CWalletDB* pwalletdbIn = nullptr, bool fExplicit = false);
//! change which version we're allowed to upgrade to (note that this does not immediately imply upgrading to that format)
bool SetMaxVersion(int nVersion);
@@ -885,12 +1038,12 @@ public:
//! Get wallet transactions that conflict with given transaction (spend same outputs)
std::set<uint256> GetConflicts(const uint256& txid) const;
+ //! Check if a given transaction has any of its outputs spent by another transaction in the wallet
+ bool HasWalletSpend(const uint256& txid) const;
+
//! Flush wallet (bitdb flush)
void Flush(bool shutdown=false);
- //! Verify the wallet database and perform salvage if required
- static bool Verify();
-
/**
* Address book entry changed.
* @note called with lock cs_wallet held.
@@ -918,64 +1071,72 @@ public:
/** Set whether this wallet broadcasts transactions. */
void SetBroadcastTransactions(bool broadcast) { fBroadcastTransactions = broadcast; }
+ /** Return whether transaction can be abandoned */
+ bool TransactionCanBeAbandoned(const uint256& hashTx) const;
+
/* Mark a transaction (and it in-wallet descendants) as abandoned so its inputs may be respent. */
bool AbandonTransaction(const uint256& hashTx);
- /* Returns the wallets help message */
- static std::string GetWalletHelpString(bool showDebug);
+ /** Mark a transaction as replaced by another transaction (e.g., BIP 125). */
+ bool MarkReplaced(const uint256& originalHash, const uint256& newHash);
/* Initializes the wallet, returns a new CWallet instance or a null pointer in case of an error */
static CWallet* CreateWalletFromFile(const std::string walletFile);
- static bool InitLoadWallet();
/**
* Wallet post-init setup
* Gives the wallet a chance to register repetitive tasks and complete post-init tasks
*/
- void postInitProcess(boost::thread_group& threadGroup);
-
- /* Wallets parameter interaction */
- static bool ParameterInteraction();
+ void postInitProcess(CScheduler& scheduler);
bool BackupWallet(const std::string& strDest);
/* Set the HD chain model (chain child index counters) */
bool SetHDChain(const CHDChain& chain, bool memonly);
- const CHDChain& GetHDChain() { return hdChain; }
+ const CHDChain& GetHDChain() const { return hdChain; }
/* Returns true if HD is enabled */
- bool IsHDEnabled();
+ bool IsHDEnabled() const;
/* Generates a new HD master key (will not be activated) */
CPubKey GenerateNewHDMasterKey();
- /* Set the current HD master key (will reset the chain child index counters) */
+ /* Set the current HD master key (will reset the chain child index counters)
+ Sets the master key's version based on the current wallet version (so the
+ caller must ensure the current wallet version is correct before calling
+ this function). */
bool SetHDMasterKey(const CPubKey& key);
};
/** A key allocated from the key pool. */
-class CReserveKey : public CReserveScript
+class CReserveKey final : public CReserveScript
{
protected:
CWallet* pwallet;
int64_t nIndex;
CPubKey vchPubKey;
+ bool fInternal;
public:
- CReserveKey(CWallet* pwalletIn)
+ explicit CReserveKey(CWallet* pwalletIn)
{
nIndex = -1;
pwallet = pwalletIn;
+ fInternal = false;
}
+ CReserveKey() = default;
+ CReserveKey(const CReserveKey&) = delete;
+ CReserveKey& operator=(const CReserveKey&) = delete;
+
~CReserveKey()
{
ReturnKey();
}
void ReturnKey();
- bool GetReservedKey(CPubKey &pubkey);
+ bool GetReservedKey(CPubKey &pubkey, bool internal = false);
void KeepKey();
- void KeepScript() { KeepKey(); }
+ void KeepScript() override { KeepKey(); }
};
@@ -1009,4 +1170,29 @@ public:
}
};
+// Helper for producing a bunch of max-sized low-S signatures (eg 72 bytes)
+// ContainerType is meant to hold pair<CWalletTx *, int>, and be iterable
+// so that each entry corresponds to each vIn, in order.
+template <typename ContainerType>
+bool CWallet::DummySignTx(CMutableTransaction &txNew, const ContainerType &coins) const
+{
+ // Fill in dummy signatures for fee calculation.
+ int nIn = 0;
+ for (const auto& coin : coins)
+ {
+ const CScript& scriptPubKey = coin.txout.scriptPubKey;
+ SignatureData sigdata;
+
+ if (!ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata))
+ {
+ return false;
+ } else {
+ UpdateTransaction(txNew, nIn, sigdata);
+ }
+
+ nIn++;
+ }
+ return true;
+}
+
#endif // BITCOIN_WALLET_WALLET_H
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 9cd19ab619..b7f873c1e4 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -6,8 +6,9 @@
#include "wallet/walletdb.h"
#include "base58.h"
+#include "consensus/tx_verify.h"
#include "consensus/validation.h"
-#include "validation.h" // For CheckTransaction
+#include "fs.h"
#include "protocol.h"
#include "serialize.h"
#include "sync.h"
@@ -15,64 +16,51 @@
#include "utiltime.h"
#include "wallet/wallet.h"
-#include <boost/version.hpp>
-#include <boost/filesystem.hpp>
-#include <boost/foreach.hpp>
-#include <boost/thread.hpp>
-
-using namespace std;
+#include <atomic>
-static uint64_t nAccountingEntryNumber = 0;
+#include <boost/thread.hpp>
//
// CWalletDB
//
-bool CWalletDB::WriteName(const string& strAddress, const string& strName)
+bool CWalletDB::WriteName(const std::string& strAddress, const std::string& strName)
{
- nWalletDBUpdated++;
- return Write(make_pair(string("name"), strAddress), strName);
+ return WriteIC(std::make_pair(std::string("name"), strAddress), strName);
}
-bool CWalletDB::EraseName(const string& strAddress)
+bool CWalletDB::EraseName(const std::string& strAddress)
{
// This should only be used for sending addresses, never for receiving addresses,
// receiving addresses must always have an address book entry if they're not change return.
- nWalletDBUpdated++;
- return Erase(make_pair(string("name"), strAddress));
+ return EraseIC(std::make_pair(std::string("name"), strAddress));
}
-bool CWalletDB::WritePurpose(const string& strAddress, const string& strPurpose)
+bool CWalletDB::WritePurpose(const std::string& strAddress, const std::string& strPurpose)
{
- nWalletDBUpdated++;
- return Write(make_pair(string("purpose"), strAddress), strPurpose);
+ return WriteIC(std::make_pair(std::string("purpose"), strAddress), strPurpose);
}
-bool CWalletDB::ErasePurpose(const string& strPurpose)
+bool CWalletDB::ErasePurpose(const std::string& strAddress)
{
- nWalletDBUpdated++;
- return Erase(make_pair(string("purpose"), strPurpose));
+ return EraseIC(std::make_pair(std::string("purpose"), strAddress));
}
bool CWalletDB::WriteTx(const CWalletTx& wtx)
{
- nWalletDBUpdated++;
- return Write(std::make_pair(std::string("tx"), wtx.GetHash()), wtx);
+ return WriteIC(std::make_pair(std::string("tx"), wtx.GetHash()), wtx);
}
bool CWalletDB::EraseTx(uint256 hash)
{
- nWalletDBUpdated++;
- return Erase(std::make_pair(std::string("tx"), hash));
+ return EraseIC(std::make_pair(std::string("tx"), hash));
}
bool CWalletDB::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta)
{
- nWalletDBUpdated++;
-
- if (!Write(std::make_pair(std::string("keymeta"), vchPubKey),
- keyMeta, false))
+ if (!WriteIC(std::make_pair(std::string("keymeta"), vchPubKey), keyMeta, false)) {
return false;
+ }
// hash pubkey/privkey to accelerate wallet load
std::vector<unsigned char> vchKey;
@@ -80,161 +68,143 @@ bool CWalletDB::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, c
vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end());
- return Write(std::make_pair(std::string("key"), vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false);
+ return WriteIC(std::make_pair(std::string("key"), vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false);
}
bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey,
const std::vector<unsigned char>& vchCryptedSecret,
const CKeyMetadata &keyMeta)
{
- const bool fEraseUnencryptedKey = true;
- nWalletDBUpdated++;
-
- if (!Write(std::make_pair(std::string("keymeta"), vchPubKey),
- keyMeta))
+ if (!WriteIC(std::make_pair(std::string("keymeta"), vchPubKey), keyMeta)) {
return false;
+ }
- if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false))
+ if (!WriteIC(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false)) {
return false;
- if (fEraseUnencryptedKey)
- {
- Erase(std::make_pair(std::string("key"), vchPubKey));
- Erase(std::make_pair(std::string("wkey"), vchPubKey));
}
+ EraseIC(std::make_pair(std::string("key"), vchPubKey));
+ EraseIC(std::make_pair(std::string("wkey"), vchPubKey));
return true;
}
bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
{
- nWalletDBUpdated++;
- return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
+ return WriteIC(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
}
bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript)
{
- nWalletDBUpdated++;
- return Write(std::make_pair(std::string("cscript"), hash), *(const CScriptBase*)(&redeemScript), false);
+ return WriteIC(std::make_pair(std::string("cscript"), hash), redeemScript, false);
}
-bool CWalletDB::WriteWatchOnly(const CScript &dest)
+bool CWalletDB::WriteWatchOnly(const CScript &dest, const CKeyMetadata& keyMeta)
{
- nWalletDBUpdated++;
- return Write(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)), '1');
+ if (!WriteIC(std::make_pair(std::string("watchmeta"), dest), keyMeta)) {
+ return false;
+ }
+ return WriteIC(std::make_pair(std::string("watchs"), dest), '1');
}
bool CWalletDB::EraseWatchOnly(const CScript &dest)
{
- nWalletDBUpdated++;
- return Erase(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)));
+ if (!EraseIC(std::make_pair(std::string("watchmeta"), dest))) {
+ return false;
+ }
+ return EraseIC(std::make_pair(std::string("watchs"), dest));
}
bool CWalletDB::WriteBestBlock(const CBlockLocator& locator)
{
- nWalletDBUpdated++;
- Write(std::string("bestblock"), CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan
- return Write(std::string("bestblock_nomerkle"), locator);
+ WriteIC(std::string("bestblock"), CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan
+ return WriteIC(std::string("bestblock_nomerkle"), locator);
}
bool CWalletDB::ReadBestBlock(CBlockLocator& locator)
{
- if (Read(std::string("bestblock"), locator) && !locator.vHave.empty()) return true;
- return Read(std::string("bestblock_nomerkle"), locator);
+ if (batch.Read(std::string("bestblock"), locator) && !locator.vHave.empty()) return true;
+ return batch.Read(std::string("bestblock_nomerkle"), locator);
}
bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext)
{
- nWalletDBUpdated++;
- return Write(std::string("orderposnext"), nOrderPosNext);
-}
-
-bool CWalletDB::WriteDefaultKey(const CPubKey& vchPubKey)
-{
- nWalletDBUpdated++;
- return Write(std::string("defaultkey"), vchPubKey);
+ return WriteIC(std::string("orderposnext"), nOrderPosNext);
}
bool CWalletDB::ReadPool(int64_t nPool, CKeyPool& keypool)
{
- return Read(std::make_pair(std::string("pool"), nPool), keypool);
+ return batch.Read(std::make_pair(std::string("pool"), nPool), keypool);
}
bool CWalletDB::WritePool(int64_t nPool, const CKeyPool& keypool)
{
- nWalletDBUpdated++;
- return Write(std::make_pair(std::string("pool"), nPool), keypool);
+ return WriteIC(std::make_pair(std::string("pool"), nPool), keypool);
}
bool CWalletDB::ErasePool(int64_t nPool)
{
- nWalletDBUpdated++;
- return Erase(std::make_pair(std::string("pool"), nPool));
+ return EraseIC(std::make_pair(std::string("pool"), nPool));
}
bool CWalletDB::WriteMinVersion(int nVersion)
{
- return Write(std::string("minversion"), nVersion);
+ return WriteIC(std::string("minversion"), nVersion);
}
-bool CWalletDB::ReadAccount(const string& strAccount, CAccount& account)
+bool CWalletDB::ReadAccount(const std::string& strAccount, CAccount& account)
{
account.SetNull();
- return Read(make_pair(string("acc"), strAccount), account);
+ return batch.Read(std::make_pair(std::string("acc"), strAccount), account);
}
-bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account)
+bool CWalletDB::WriteAccount(const std::string& strAccount, const CAccount& account)
{
- return Write(make_pair(string("acc"), strAccount), account);
+ return WriteIC(std::make_pair(std::string("acc"), strAccount), account);
}
bool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry)
{
- return Write(std::make_pair(std::string("acentry"), std::make_pair(acentry.strAccount, nAccEntryNum)), acentry);
+ return WriteIC(std::make_pair(std::string("acentry"), std::make_pair(acentry.strAccount, nAccEntryNum)), acentry);
}
-bool CWalletDB::WriteAccountingEntry_Backend(const CAccountingEntry& acentry)
+CAmount CWalletDB::GetAccountCreditDebit(const std::string& strAccount)
{
- return WriteAccountingEntry(++nAccountingEntryNumber, acentry);
-}
-
-CAmount CWalletDB::GetAccountCreditDebit(const string& strAccount)
-{
- list<CAccountingEntry> entries;
+ std::list<CAccountingEntry> entries;
ListAccountCreditDebit(strAccount, entries);
CAmount nCreditDebit = 0;
- BOOST_FOREACH (const CAccountingEntry& entry, entries)
+ for (const CAccountingEntry& entry : entries)
nCreditDebit += entry.nCreditDebit;
return nCreditDebit;
}
-void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountingEntry>& entries)
+void CWalletDB::ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries)
{
bool fAllAccounts = (strAccount == "*");
- Dbc* pcursor = GetCursor();
+ Dbc* pcursor = batch.GetCursor();
if (!pcursor)
- throw runtime_error(std::string(__func__) + ": cannot create DB cursor");
+ throw std::runtime_error(std::string(__func__) + ": cannot create DB cursor");
bool setRange = true;
while (true)
{
// Read next record
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
if (setRange)
- ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? string("") : strAccount), uint64_t(0)));
+ ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? std::string("") : strAccount), uint64_t(0)));
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
- int ret = ReadAtCursor(pcursor, ssKey, ssValue, setRange);
+ int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue, setRange);
setRange = false;
if (ret == DB_NOTFOUND)
break;
else if (ret != 0)
{
pcursor->close();
- throw runtime_error(std::string(__func__) + ": error scanning DB");
+ throw std::runtime_error(std::string(__func__) + ": error scanning DB");
}
// Unserialize
- string strType;
+ std::string strType;
ssKey >> strType;
if (strType != "acentry")
break;
@@ -255,14 +225,15 @@ class CWalletScanState {
public:
unsigned int nKeys;
unsigned int nCKeys;
+ unsigned int nWatchKeys;
unsigned int nKeyMeta;
bool fIsEncrypted;
bool fAnyUnordered;
int nFileVersion;
- vector<uint256> vWalletUpgrade;
+ std::vector<uint256> vWalletUpgrade;
CWalletScanState() {
- nKeys = nCKeys = nKeyMeta = 0;
+ nKeys = nCKeys = nWatchKeys = nKeyMeta = 0;
fIsEncrypted = false;
fAnyUnordered = false;
nFileVersion = 0;
@@ -271,7 +242,7 @@ public:
bool
ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
- CWalletScanState &wss, string& strType, string& strErr)
+ CWalletScanState &wss, std::string& strType, std::string& strErr)
{
try {
// Unserialize
@@ -280,15 +251,15 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
ssKey >> strType;
if (strType == "name")
{
- string strAddress;
+ std::string strAddress;
ssKey >> strAddress;
- ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].name;
+ ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].name;
}
else if (strType == "purpose")
{
- string strAddress;
+ std::string strAddress;
ssKey >> strAddress;
- ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].purpose;
+ ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].purpose;
}
else if (strType == "tx")
{
@@ -327,12 +298,13 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
}
else if (strType == "acentry")
{
- string strAccount;
+ std::string strAccount;
ssKey >> strAccount;
uint64_t nNumber;
ssKey >> nNumber;
- if (nNumber > nAccountingEntryNumber)
- nAccountingEntryNumber = nNumber;
+ if (nNumber > pwallet->nAccountingEntryNumber) {
+ pwallet->nAccountingEntryNumber = nNumber;
+ }
if (!wss.fAnyUnordered)
{
@@ -344,16 +316,13 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
}
else if (strType == "watchs")
{
+ wss.nWatchKeys++;
CScript script;
- ssKey >> *(CScriptBase*)(&script);
+ ssKey >> script;
char fYes;
ssValue >> fYes;
if (fYes == '1')
pwallet->LoadWatchOnly(script);
-
- // Watch-only addresses have no birthday information for now,
- // so set the wallet birthday to the beginning of time.
- pwallet->nTimeFirstKey = 1;
}
else if (strType == "key" || strType == "wkey")
{
@@ -443,7 +412,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
strErr = "Error reading wallet database: CPubKey corrupt";
return false;
}
- vector<unsigned char> vchPrivKey;
+ std::vector<unsigned char> vchPrivKey;
ssValue >> vchPrivKey;
wss.nCKeys++;
@@ -454,24 +423,38 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
}
wss.fIsEncrypted = true;
}
- else if (strType == "keymeta")
+ else if (strType == "keymeta" || strType == "watchmeta")
{
- CPubKey vchPubKey;
- ssKey >> vchPubKey;
+ CTxDestination keyID;
+ if (strType == "keymeta")
+ {
+ CPubKey vchPubKey;
+ ssKey >> vchPubKey;
+ keyID = vchPubKey.GetID();
+ }
+ else if (strType == "watchmeta")
+ {
+ CScript script;
+ ssKey >> script;
+ keyID = CScriptID(script);
+ }
+
CKeyMetadata keyMeta;
ssValue >> keyMeta;
wss.nKeyMeta++;
- pwallet->LoadKeyMetadata(vchPubKey, keyMeta);
-
- // find earliest key creation time, as wallet birthday
- if (!pwallet->nTimeFirstKey ||
- (keyMeta.nCreateTime < pwallet->nTimeFirstKey))
- pwallet->nTimeFirstKey = keyMeta.nCreateTime;
+ pwallet->LoadKeyMetadata(keyID, keyMeta);
}
else if (strType == "defaultkey")
{
- ssValue >> pwallet->vchDefaultKey;
+ // We don't want or need the default key, but if there is one set,
+ // we want to make sure that it is valid so that we can detect corruption
+ CPubKey vchPubKey;
+ ssValue >> vchPubKey;
+ if (!vchPubKey.IsValid()) {
+ strErr = "Error reading wallet database: Default Key corrupt";
+ return false;
+ }
}
else if (strType == "pool")
{
@@ -493,7 +476,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
uint160 hash;
ssKey >> hash;
CScript script;
- ssValue >> *(CScriptBase*)(&script);
+ ssValue >> script;
if (!pwallet->LoadCScript(script))
{
strErr = "Error reading wallet database: LoadCScript failed";
@@ -510,7 +493,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
ssKey >> strAddress;
ssKey >> strKey;
ssValue >> strValue;
- if (!pwallet->LoadDestData(CBitcoinAddress(strAddress).Get(), strKey, strValue))
+ if (!pwallet->LoadDestData(DecodeDestination(strAddress), strKey, strValue))
{
strErr = "Error reading wallet database: LoadDestData failed";
return false;
@@ -533,7 +516,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
return true;
}
-static bool IsKeyType(string strType)
+bool CWalletDB::IsKeyType(const std::string& strType)
{
return (strType== "key" || strType == "wkey" ||
strType == "mkey" || strType == "ckey");
@@ -541,15 +524,14 @@ static bool IsKeyType(string strType)
DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
{
- pwallet->vchDefaultKey = CPubKey();
CWalletScanState wss;
bool fNoncriticalErrors = false;
DBErrors result = DB_LOAD_OK;
+ LOCK(pwallet->cs_wallet);
try {
- LOCK(pwallet->cs_wallet);
int nMinVersion = 0;
- if (Read((string)"minversion", nMinVersion))
+ if (batch.Read((std::string)"minversion", nMinVersion))
{
if (nMinVersion > CLIENT_VERSION)
return DB_TOO_NEW;
@@ -557,7 +539,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
}
// Get cursor
- Dbc* pcursor = GetCursor();
+ Dbc* pcursor = batch.GetCursor();
if (!pcursor)
{
LogPrintf("Error getting wallet database cursor\n");
@@ -569,7 +551,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
// Read next record
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
- int ret = ReadAtCursor(pcursor, ssKey, ssValue);
+ int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue);
if (ret == DB_NOTFOUND)
break;
else if (ret != 0)
@@ -579,12 +561,12 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
}
// Try to be tolerant of single corrupt records:
- string strType, strErr;
+ std::string strType, strErr;
if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr))
{
// losing keys is considered a catastrophic error, anything else
// we assume the user can live with:
- if (IsKeyType(strType))
+ if (IsKeyType(strType) || strType == "defaultkey")
result = DB_CORRUPT;
else
{
@@ -592,7 +574,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
fNoncriticalErrors = true; // ... but do warn the user there is something wrong.
if (strType == "tx")
// Rescan if there is a bad transaction record:
- SoftSetBoolArg("-rescan", true);
+ gArgs.SoftSetBoolArg("-rescan", true);
}
}
if (!strErr.empty())
@@ -621,10 +603,10 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys);
// nTimeFirstKey is only reliable if all keys have metadata
- if ((wss.nKeys + wss.nCKeys) != wss.nKeyMeta)
- pwallet->nTimeFirstKey = 1; // 0 would be considered 'no value'
+ if ((wss.nKeys + wss.nCKeys + wss.nWatchKeys) != wss.nKeyMeta)
+ pwallet->UpdateTimeFirstKey(1);
- BOOST_FOREACH(uint256 hash, wss.vWalletUpgrade)
+ for (uint256 hash : wss.vWalletUpgrade)
WriteTx(pwallet->mapWallet[hash]);
// Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
@@ -639,31 +621,28 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
pwallet->laccentries.clear();
ListAccountCreditDebit("*", pwallet->laccentries);
- BOOST_FOREACH(CAccountingEntry& entry, pwallet->laccentries) {
- pwallet->wtxOrdered.insert(make_pair(entry.nOrderPos, CWallet::TxPair((CWalletTx*)0, &entry)));
+ for (CAccountingEntry& entry : pwallet->laccentries) {
+ pwallet->wtxOrdered.insert(make_pair(entry.nOrderPos, CWallet::TxPair(nullptr, &entry)));
}
return result;
}
-DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector<uint256>& vTxHash, vector<CWalletTx>& vWtx)
+DBErrors CWalletDB::FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx)
{
- pwallet->vchDefaultKey = CPubKey();
bool fNoncriticalErrors = false;
DBErrors result = DB_LOAD_OK;
try {
- LOCK(pwallet->cs_wallet);
int nMinVersion = 0;
- if (Read((string)"minversion", nMinVersion))
+ if (batch.Read((std::string)"minversion", nMinVersion))
{
if (nMinVersion > CLIENT_VERSION)
return DB_TOO_NEW;
- pwallet->LoadMinVersion(nMinVersion);
}
// Get cursor
- Dbc* pcursor = GetCursor();
+ Dbc* pcursor = batch.GetCursor();
if (!pcursor)
{
LogPrintf("Error getting wallet database cursor\n");
@@ -675,7 +654,7 @@ DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector<uint256>& vTxHash, vec
// Read next record
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
- int ret = ReadAtCursor(pcursor, ssKey, ssValue);
+ int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue);
if (ret == DB_NOTFOUND)
break;
else if (ret != 0)
@@ -684,7 +663,7 @@ DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector<uint256>& vTxHash, vec
return DB_CORRUPT;
}
- string strType;
+ std::string strType;
ssKey >> strType;
if (strType == "tx") {
uint256 hash;
@@ -712,12 +691,12 @@ DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector<uint256>& vTxHash, vec
return result;
}
-DBErrors CWalletDB::ZapSelectTx(CWallet* pwallet, vector<uint256>& vTxHashIn, vector<uint256>& vTxHashOut)
+DBErrors CWalletDB::ZapSelectTx(std::vector<uint256>& vTxHashIn, std::vector<uint256>& vTxHashOut)
{
// build list of wallet TXs and hashes
- vector<uint256> vTxHash;
- vector<CWalletTx> vWtx;
- DBErrors err = FindWalletTx(pwallet, vTxHash, vWtx);
+ std::vector<uint256> vTxHash;
+ std::vector<CWalletTx> vWtx;
+ DBErrors err = FindWalletTx(vTxHash, vWtx);
if (err != DB_LOAD_OK) {
return err;
}
@@ -727,8 +706,8 @@ DBErrors CWalletDB::ZapSelectTx(CWallet* pwallet, vector<uint256>& vTxHashIn, ve
// erase each matching wallet TX
bool delerror = false;
- vector<uint256>::iterator it = vTxHashIn.begin();
- BOOST_FOREACH (uint256 hash, vTxHash) {
+ std::vector<uint256>::iterator it = vTxHashIn.begin();
+ for (uint256 hash : vTxHash) {
while (it < vTxHashIn.end() && (*it) < hash) {
it++;
}
@@ -736,9 +715,8 @@ DBErrors CWalletDB::ZapSelectTx(CWallet* pwallet, vector<uint256>& vTxHashIn, ve
break;
}
else if ((*it) == hash) {
- pwallet->mapWallet.erase(hash);
if(!EraseTx(hash)) {
- LogPrint("db", "Transaction was found for deletion but returned database error: %s\n", hash.GetHex());
+ LogPrint(BCLog::DB, "Transaction was found for deletion but returned database error: %s\n", hash.GetHex());
delerror = true;
}
vTxHashOut.push_back(hash);
@@ -751,16 +729,16 @@ DBErrors CWalletDB::ZapSelectTx(CWallet* pwallet, vector<uint256>& vTxHashIn, ve
return DB_LOAD_OK;
}
-DBErrors CWalletDB::ZapWalletTx(CWallet* pwallet, vector<CWalletTx>& vWtx)
+DBErrors CWalletDB::ZapWalletTx(std::vector<CWalletTx>& vWtx)
{
// build list of wallet TXs
- vector<uint256> vTxHash;
- DBErrors err = FindWalletTx(pwallet, vTxHash, vWtx);
+ std::vector<uint256> vTxHash;
+ DBErrors err = FindWalletTx(vTxHash, vWtx);
if (err != DB_LOAD_OK)
return err;
// erase each wallet TX
- BOOST_FOREACH (uint256& hash, vTxHash) {
+ for (uint256& hash : vTxHash) {
if (!EraseTx(hash))
return DB_CORRUPT;
}
@@ -768,173 +746,121 @@ DBErrors CWalletDB::ZapWalletTx(CWallet* pwallet, vector<CWalletTx>& vWtx)
return DB_LOAD_OK;
}
-void ThreadFlushWalletDB()
+void MaybeCompactWalletDB()
{
- // Make this thread recognisable as the wallet flushing thread
- RenameThread("bitcoin-wallet");
-
- static bool fOneThread;
- if (fOneThread)
+ static std::atomic<bool> fOneThread(false);
+ if (fOneThread.exchange(true)) {
return;
- fOneThread = true;
- if (!GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET))
+ }
+ if (!gArgs.GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET)) {
return;
+ }
- unsigned int nLastSeen = nWalletDBUpdated;
- unsigned int nLastFlushed = nWalletDBUpdated;
- int64_t nLastWalletUpdate = GetTime();
- while (true)
- {
- MilliSleep(500);
+ for (CWalletRef pwallet : vpwallets) {
+ CWalletDBWrapper& dbh = pwallet->GetDBHandle();
- if (nLastSeen != nWalletDBUpdated)
- {
- nLastSeen = nWalletDBUpdated;
- nLastWalletUpdate = GetTime();
- }
+ unsigned int nUpdateCounter = dbh.nUpdateCounter;
- if (nLastFlushed != nWalletDBUpdated && GetTime() - nLastWalletUpdate >= 2)
- {
- TRY_LOCK(bitdb.cs_db,lockDb);
- if (lockDb)
- {
- // Don't do this if any databases are in use
- int nRefCount = 0;
- map<string, int>::iterator mi = bitdb.mapFileUseCount.begin();
- while (mi != bitdb.mapFileUseCount.end())
- {
- nRefCount += (*mi).second;
- mi++;
- }
+ if (dbh.nLastSeen != nUpdateCounter) {
+ dbh.nLastSeen = nUpdateCounter;
+ dbh.nLastWalletUpdate = GetTime();
+ }
- if (nRefCount == 0)
- {
- boost::this_thread::interruption_point();
- const std::string& strFile = pwalletMain->strWalletFile;
- map<string, int>::iterator _mi = bitdb.mapFileUseCount.find(strFile);
- if (_mi != bitdb.mapFileUseCount.end())
- {
- LogPrint("db", "Flushing %s\n", strFile);
- nLastFlushed = nWalletDBUpdated;
- int64_t nStart = GetTimeMillis();
-
- // Flush wallet file so it's self contained
- bitdb.CloseDb(strFile);
- bitdb.CheckpointLSN(strFile);
-
- bitdb.mapFileUseCount.erase(_mi++);
- LogPrint("db", "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart);
- }
- }
+ if (dbh.nLastFlushed != nUpdateCounter && GetTime() - dbh.nLastWalletUpdate >= 2) {
+ if (CDB::PeriodicFlush(dbh)) {
+ dbh.nLastFlushed = nUpdateCounter;
}
}
}
+
+ fOneThread = false;
}
//
// Try to (very carefully!) recover wallet file if there is a problem.
//
-bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKeys)
-{
- // Recovery procedure:
- // move wallet file to wallet.timestamp.bak
- // Call Salvage with fAggressive=true to
- // get as much data as possible.
- // Rewrite salvaged data to fresh wallet file
- // Set -rescan so any missing transactions will be
- // found.
- int64_t now = GetTime();
- std::string newFilename = strprintf("wallet.%d.bak", now);
-
- int result = dbenv.dbenv->dbrename(NULL, filename.c_str(), NULL,
- newFilename.c_str(), DB_AUTO_COMMIT);
- if (result == 0)
- LogPrintf("Renamed %s to %s\n", filename, newFilename);
- else
- {
- LogPrintf("Failed to rename %s to %s\n", filename, newFilename);
- return false;
- }
+bool CWalletDB::Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& out_backup_filename)
+{
+ return CDB::Recover(filename, callbackDataIn, recoverKVcallback, out_backup_filename);
+}
- std::vector<CDBEnv::KeyValPair> salvagedData;
- bool fSuccess = dbenv.Salvage(newFilename, true, salvagedData);
- if (salvagedData.empty())
+bool CWalletDB::Recover(const std::string& filename, std::string& out_backup_filename)
+{
+ // recover without a key filter callback
+ // results in recovering all record types
+ return CWalletDB::Recover(filename, nullptr, nullptr, out_backup_filename);
+}
+
+bool CWalletDB::RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, CDataStream ssValue)
+{
+ CWallet *dummyWallet = reinterpret_cast<CWallet*>(callbackData);
+ CWalletScanState dummyWss;
+ std::string strType, strErr;
+ bool fReadOK;
{
- LogPrintf("Salvage(aggressive) found no records in %s.\n", newFilename);
- return false;
+ // Required in LoadKeyMetadata():
+ LOCK(dummyWallet->cs_wallet);
+ fReadOK = ReadKeyValue(dummyWallet, ssKey, ssValue,
+ dummyWss, strType, strErr);
}
- LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size());
-
- std::unique_ptr<Db> pdbCopy(new Db(dbenv.dbenv, 0));
- int ret = pdbCopy->open(NULL, // Txn pointer
- filename.c_str(), // Filename
- "main", // Logical db name
- DB_BTREE, // Database type
- DB_CREATE, // Flags
- 0);
- if (ret > 0)
+ if (!IsKeyType(strType) && strType != "hdchain")
+ return false;
+ if (!fReadOK)
{
- LogPrintf("Cannot create database file %s\n", filename);
+ LogPrintf("WARNING: CWalletDB::Recover skipping %s: %s\n", strType, strErr);
return false;
}
- CWallet dummyWallet;
- CWalletScanState wss;
- DbTxn* ptxn = dbenv.TxnBegin();
- BOOST_FOREACH(CDBEnv::KeyValPair& row, salvagedData)
- {
- if (fOnlyKeys)
- {
- CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION);
- CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION);
- string strType, strErr;
- bool fReadOK;
- {
- // Required in LoadKeyMetadata():
- LOCK(dummyWallet.cs_wallet);
- fReadOK = ReadKeyValue(&dummyWallet, ssKey, ssValue,
- wss, strType, strErr);
- }
- if (!IsKeyType(strType) && strType != "hdchain")
- continue;
- if (!fReadOK)
- {
- LogPrintf("WARNING: CWalletDB::Recover skipping %s: %s\n", strType, strErr);
- continue;
- }
- }
- Dbt datKey(&row.first[0], row.first.size());
- Dbt datValue(&row.second[0], row.second.size());
- int ret2 = pdbCopy->put(ptxn, &datKey, &datValue, DB_NOOVERWRITE);
- if (ret2 > 0)
- fSuccess = false;
- }
- ptxn->commit(0);
- pdbCopy->close(0);
+ return true;
+}
- return fSuccess;
+bool CWalletDB::VerifyEnvironment(const std::string& walletFile, const fs::path& dataDir, std::string& errorStr)
+{
+ return CDB::VerifyEnvironment(walletFile, dataDir, errorStr);
}
-bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename)
+bool CWalletDB::VerifyDatabaseFile(const std::string& walletFile, const fs::path& dataDir, std::string& warningStr, std::string& errorStr)
{
- return CWalletDB::Recover(dbenv, filename, false);
+ return CDB::VerifyDatabaseFile(walletFile, dataDir, warningStr, errorStr, CWalletDB::Recover);
}
bool CWalletDB::WriteDestData(const std::string &address, const std::string &key, const std::string &value)
{
- nWalletDBUpdated++;
- return Write(std::make_pair(std::string("destdata"), std::make_pair(address, key)), value);
+ return WriteIC(std::make_pair(std::string("destdata"), std::make_pair(address, key)), value);
}
bool CWalletDB::EraseDestData(const std::string &address, const std::string &key)
{
- nWalletDBUpdated++;
- return Erase(std::make_pair(std::string("destdata"), std::make_pair(address, key)));
+ return EraseIC(std::make_pair(std::string("destdata"), std::make_pair(address, key)));
}
bool CWalletDB::WriteHDChain(const CHDChain& chain)
{
- nWalletDBUpdated++;
- return Write(std::string("hdchain"), chain);
+ return WriteIC(std::string("hdchain"), chain);
+}
+
+bool CWalletDB::TxnBegin()
+{
+ return batch.TxnBegin();
+}
+
+bool CWalletDB::TxnCommit()
+{
+ return batch.TxnCommit();
+}
+
+bool CWalletDB::TxnAbort()
+{
+ return batch.TxnAbort();
+}
+
+bool CWalletDB::ReadVersion(int& nVersion)
+{
+ return batch.ReadVersion(nVersion);
+}
+
+bool CWalletDB::WriteVersion(int nVersion)
+{
+ return batch.WriteVersion(nVersion);
}
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index b9db55baa4..3a146179af 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -17,6 +17,21 @@
#include <utility>
#include <vector>
+/**
+ * Overview of wallet database classes:
+ *
+ * - CDBEnv is an environment in which the database exists (has no analog in dbwrapper.h)
+ * - CWalletDBWrapper represents a wallet database (similar to CDBWrapper in dbwrapper.h)
+ * - CDB is a low-level database transaction (similar to CDBBatch in dbwrapper.h)
+ * - CWalletDB is a modifier object for the wallet, and encapsulates a database
+ * transaction as well as methods to act on the database (no analog in
+ * dbwrapper.h)
+ *
+ * The latter two are named confusingly, in contrast to what the names CDB
+ * and CWalletDB suggest they are transient transaction objects and don't
+ * represent the database itself.
+ */
+
static const bool DEFAULT_FLUSHWALLET = true;
class CAccount;
@@ -46,9 +61,12 @@ class CHDChain
{
public:
uint32_t nExternalChainCounter;
+ uint32_t nInternalChainCounter;
CKeyID masterKeyID; //!< master key hash160
- static const int CURRENT_VERSION = 1;
+ static const int VERSION_HD_BASE = 1;
+ static const int VERSION_HD_CHAIN_SPLIT = 2;
+ static const int CURRENT_VERSION = VERSION_HD_CHAIN_SPLIT;
int nVersion;
CHDChain() { SetNull(); }
@@ -59,12 +77,15 @@ public:
READWRITE(this->nVersion);
READWRITE(nExternalChainCounter);
READWRITE(masterKeyID);
+ if (this->nVersion >= VERSION_HD_CHAIN_SPLIT)
+ READWRITE(nInternalChainCounter);
}
void SetNull()
{
nVersion = CHDChain::CURRENT_VERSION;
nExternalChainCounter = 0;
+ nInternalChainCounter = 0;
masterKeyID.SetNull();
}
};
@@ -84,7 +105,7 @@ public:
{
SetNull();
}
- CKeyMetadata(int64_t nCreateTime_)
+ explicit CKeyMetadata(int64_t nCreateTime_)
{
SetNull();
nCreateTime = nCreateTime_;
@@ -112,13 +133,42 @@ public:
}
};
-/** Access to the wallet database */
-class CWalletDB : public CDB
+/** Access to the wallet database.
+ * This should really be named CWalletDBBatch, as it represents a single transaction at the
+ * database. It will be committed when the object goes out of scope.
+ * Optionally (on by default) it will flush to disk as well.
+ */
+class CWalletDB
{
+private:
+ template <typename K, typename T>
+ bool WriteIC(const K& key, const T& value, bool fOverwrite = true)
+ {
+ if (!batch.Write(key, value, fOverwrite)) {
+ return false;
+ }
+ m_dbw.IncrementUpdateCounter();
+ return true;
+ }
+
+ template <typename K>
+ bool EraseIC(const K& key)
+ {
+ if (!batch.Erase(key)) {
+ return false;
+ }
+ m_dbw.IncrementUpdateCounter();
+ return true;
+ }
+
public:
- CWalletDB(const std::string& strFilename, const char* pszMode = "r+", bool fFlushOnClose = true) : CDB(strFilename, pszMode, fFlushOnClose)
+ explicit CWalletDB(CWalletDBWrapper& dbw, const char* pszMode = "r+", bool _fFlushOnClose = true) :
+ batch(dbw, pszMode, _fFlushOnClose),
+ m_dbw(dbw)
{
}
+ CWalletDB(const CWalletDB&) = delete;
+ CWalletDB& operator=(const CWalletDB&) = delete;
bool WriteName(const std::string& strAddress, const std::string& strName);
bool EraseName(const std::string& strAddress);
@@ -135,7 +185,7 @@ public:
bool WriteCScript(const uint160& hash, const CScript& redeemScript);
- bool WriteWatchOnly(const CScript &script);
+ bool WriteWatchOnly(const CScript &script, const CKeyMetadata &keymeta);
bool EraseWatchOnly(const CScript &script);
bool WriteBestBlock(const CBlockLocator& locator);
@@ -143,8 +193,6 @@ public:
bool WriteOrderPosNext(int64_t nOrderPosNext);
- bool WriteDefaultKey(const CPubKey& vchPubKey);
-
bool ReadPool(int64_t nPool, CKeyPool& keypool);
bool WritePool(int64_t nPool, const CKeyPool& keypool);
bool ErasePool(int64_t nPool);
@@ -154,7 +202,6 @@ public:
/// This writes directly to the database, and will not update the CWallet's cached accounting entries!
/// Use wallet.AddAccountingEntry instead, to write *and* update its caches.
bool WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry);
- bool WriteAccountingEntry_Backend(const CAccountingEntry& acentry);
bool ReadAccount(const std::string& strAccount, CAccount& account);
bool WriteAccount(const std::string& strAccount, const CAccount& account);
@@ -167,21 +214,41 @@ public:
void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries);
DBErrors LoadWallet(CWallet* pwallet);
- DBErrors FindWalletTx(CWallet* pwallet, std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx);
- DBErrors ZapWalletTx(CWallet* pwallet, std::vector<CWalletTx>& vWtx);
- DBErrors ZapSelectTx(CWallet* pwallet, std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut);
- static bool Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKeys);
- static bool Recover(CDBEnv& dbenv, const std::string& filename);
+ DBErrors FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx);
+ DBErrors ZapWalletTx(std::vector<CWalletTx>& vWtx);
+ DBErrors ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut);
+ /* Try to (very carefully!) recover wallet database (with a possible key type filter) */
+ static bool Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& out_backup_filename);
+ /* Recover convenience-function to bypass the key filter callback, called when verify fails, recovers everything */
+ static bool Recover(const std::string& filename, std::string& out_backup_filename);
+ /* Recover filter (used as callback), will only let keys (cryptographical keys) as KV/key-type pass through */
+ static bool RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, CDataStream ssValue);
+ /* Function to determine if a certain KV/key-type is a key (cryptographical key) type */
+ static bool IsKeyType(const std::string& strType);
+ /* verifies the database environment */
+ static bool VerifyEnvironment(const std::string& walletFile, const fs::path& dataDir, std::string& errorStr);
+ /* verifies the database file */
+ static bool VerifyDatabaseFile(const std::string& walletFile, const fs::path& dataDir, std::string& warningStr, std::string& errorStr);
//! write the hdchain model (external chain child index counter)
bool WriteHDChain(const CHDChain& chain);
+ //! Begin a new transaction
+ bool TxnBegin();
+ //! Commit current transaction
+ bool TxnCommit();
+ //! Abort current transaction
+ bool TxnAbort();
+ //! Read wallet version
+ bool ReadVersion(int& nVersion);
+ //! Write wallet version
+ bool WriteVersion(int nVersion);
private:
- CWalletDB(const CWalletDB&);
- void operator=(const CWalletDB&);
-
+ CDB batch;
+ CWalletDBWrapper& m_dbw;
};
-void ThreadFlushWalletDB();
+//! Compacts BDB state so that wallet.dat is self-contained (if there are changes)
+void MaybeCompactWalletDB();
#endif // BITCOIN_WALLET_WALLETDB_H
diff --git a/src/warnings.cpp b/src/warnings.cpp
index 2c1b1b0e12..d4e33b701a 100644
--- a/src/warnings.cpp
+++ b/src/warnings.cpp
@@ -37,12 +37,6 @@ void SetfLargeWorkInvalidChainFound(bool flag)
fLargeWorkInvalidChainFound = flag;
}
-bool GetfLargeWorkInvalidChainFound()
-{
- LOCK(cs_warnings);
- return fLargeWorkInvalidChainFound;
-}
-
std::string GetWarnings(const std::string& strFor)
{
std::string strStatusBar;
@@ -57,7 +51,7 @@ std::string GetWarnings(const std::string& strFor)
strGUI = _("This is a pre-release test build - use at your own risk - do not use for mining or merchant applications");
}
- if (GetBoolArg("-testsafemode", DEFAULT_TESTSAFEMODE))
+ if (gArgs.GetBoolArg("-testsafemode", DEFAULT_TESTSAFEMODE))
strStatusBar = strRPC = strGUI = "testsafemode enabled";
// Misc warnings like out of disk space and clock is wrong
diff --git a/src/warnings.h b/src/warnings.h
index a7aa657426..e8e982c0e3 100644
--- a/src/warnings.h
+++ b/src/warnings.h
@@ -13,7 +13,13 @@ void SetMiscWarning(const std::string& strWarning);
void SetfLargeWorkForkFound(bool flag);
bool GetfLargeWorkForkFound();
void SetfLargeWorkInvalidChainFound(bool flag);
-bool GetfLargeWorkInvalidChainFound();
+/** Format a string that describes several potential problems detected by the core.
+ * strFor can have three values:
+ * - "rpc": get critical warnings, which should put the client in safe mode if non-empty
+ * - "statusbar": get all warnings
+ * - "gui": get all warnings, translated (where possible) for GUI
+ * This function only returns the highest priority warning of the set selected by strFor.
+ */
std::string GetWarnings(const std::string& strFor);
static const bool DEFAULT_TESTSAFEMODE = false;
diff --git a/src/zmq/zmqabstractnotifier.h b/src/zmq/zmqabstractnotifier.h
index 77cf5141e2..7828822149 100644
--- a/src/zmq/zmqabstractnotifier.h
+++ b/src/zmq/zmqabstractnotifier.h
@@ -15,7 +15,7 @@ typedef CZMQAbstractNotifier* (*CZMQNotifierFactory)();
class CZMQAbstractNotifier
{
public:
- CZMQAbstractNotifier() : psocket(0) { }
+ CZMQAbstractNotifier() : psocket(nullptr) { }
virtual ~CZMQAbstractNotifier();
template <typename T>
diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp
index 431d8c9ac9..9909395d84 100644
--- a/src/zmq/zmqnotificationinterface.cpp
+++ b/src/zmq/zmqnotificationinterface.cpp
@@ -12,10 +12,10 @@
void zmqError(const char *str)
{
- LogPrint("zmq", "zmq: Error: %s, errno=%s\n", str, zmq_strerror(errno));
+ LogPrint(BCLog::ZMQ, "zmq: Error: %s, errno=%s\n", str, zmq_strerror(errno));
}
-CZMQNotificationInterface::CZMQNotificationInterface() : pcontext(NULL)
+CZMQNotificationInterface::CZMQNotificationInterface() : pcontext(nullptr)
{
}
@@ -31,7 +31,7 @@ CZMQNotificationInterface::~CZMQNotificationInterface()
CZMQNotificationInterface* CZMQNotificationInterface::Create()
{
- CZMQNotificationInterface* notificationInterface = NULL;
+ CZMQNotificationInterface* notificationInterface = nullptr;
std::map<std::string, CZMQNotifierFactory> factories;
std::list<CZMQAbstractNotifier*> notifiers;
@@ -43,10 +43,10 @@ CZMQNotificationInterface* CZMQNotificationInterface::Create()
for (std::map<std::string, CZMQNotifierFactory>::const_iterator i=factories.begin(); i!=factories.end(); ++i)
{
std::string arg("-zmq" + i->first);
- if (IsArgSet(arg))
+ if (gArgs.IsArgSet(arg))
{
CZMQNotifierFactory factory = i->second;
- std::string address = GetArg(arg, "");
+ std::string address = gArgs.GetArg(arg, "");
CZMQAbstractNotifier *notifier = factory();
notifier->SetType(i->first);
notifier->SetAddress(address);
@@ -62,7 +62,7 @@ CZMQNotificationInterface* CZMQNotificationInterface::Create()
if (!notificationInterface->Initialize())
{
delete notificationInterface;
- notificationInterface = NULL;
+ notificationInterface = nullptr;
}
}
@@ -72,7 +72,7 @@ CZMQNotificationInterface* CZMQNotificationInterface::Create()
// Called at startup to conditionally set up ZMQ socket(s)
bool CZMQNotificationInterface::Initialize()
{
- LogPrint("zmq", "zmq: Initialize notification interface\n");
+ LogPrint(BCLog::ZMQ, "zmq: Initialize notification interface\n");
assert(!pcontext);
pcontext = zmq_init(1);
@@ -89,11 +89,11 @@ bool CZMQNotificationInterface::Initialize()
CZMQAbstractNotifier *notifier = *i;
if (notifier->Initialize(pcontext))
{
- LogPrint("zmq", " Notifier %s ready (address = %s)\n", notifier->GetType(), notifier->GetAddress());
+ LogPrint(BCLog::ZMQ, " Notifier %s ready (address = %s)\n", notifier->GetType(), notifier->GetAddress());
}
else
{
- LogPrint("zmq", " Notifier %s failed (address = %s)\n", notifier->GetType(), notifier->GetAddress());
+ LogPrint(BCLog::ZMQ, " Notifier %s failed (address = %s)\n", notifier->GetType(), notifier->GetAddress());
break;
}
}
@@ -109,18 +109,18 @@ bool CZMQNotificationInterface::Initialize()
// Called during shutdown sequence
void CZMQNotificationInterface::Shutdown()
{
- LogPrint("zmq", "zmq: Shutdown notification interface\n");
+ LogPrint(BCLog::ZMQ, "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());
+ LogPrint(BCLog::ZMQ, " Shutdown notifier %s at %s\n", notifier->GetType(), notifier->GetAddress());
notifier->Shutdown();
}
zmq_ctx_destroy(pcontext);
- pcontext = 0;
+ pcontext = nullptr;
}
}
@@ -144,8 +144,12 @@ void CZMQNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, co
}
}
-void CZMQNotificationInterface::SyncTransaction(const CTransaction& tx, const CBlockIndex* pindex, int posInBlock)
+void CZMQNotificationInterface::TransactionAddedToMempool(const CTransactionRef& ptx)
{
+ // Used by BlockConnected and BlockDisconnected as well, because they're
+ // all the same external callback.
+ const CTransaction& tx = *ptx;
+
for (std::list<CZMQAbstractNotifier*>::iterator i = notifiers.begin(); i!=notifiers.end(); )
{
CZMQAbstractNotifier *notifier = *i;
@@ -160,3 +164,19 @@ void CZMQNotificationInterface::SyncTransaction(const CTransaction& tx, const CB
}
}
}
+
+void CZMQNotificationInterface::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected, const std::vector<CTransactionRef>& vtxConflicted)
+{
+ for (const CTransactionRef& ptx : pblock->vtx) {
+ // Do a normal notify for each transaction added in the block
+ TransactionAddedToMempool(ptx);
+ }
+}
+
+void CZMQNotificationInterface::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock)
+{
+ for (const CTransactionRef& ptx : pblock->vtx) {
+ // Do a normal notify for each transaction removed in block disconnection
+ TransactionAddedToMempool(ptx);
+ }
+}
diff --git a/src/zmq/zmqnotificationinterface.h b/src/zmq/zmqnotificationinterface.h
index beabb78da6..cb92216fa4 100644
--- a/src/zmq/zmqnotificationinterface.h
+++ b/src/zmq/zmqnotificationinterface.h
@@ -8,11 +8,12 @@
#include "validationinterface.h"
#include <string>
#include <map>
+#include <list>
class CBlockIndex;
class CZMQAbstractNotifier;
-class CZMQNotificationInterface : public CValidationInterface
+class CZMQNotificationInterface final : public CValidationInterface
{
public:
virtual ~CZMQNotificationInterface();
@@ -24,8 +25,10 @@ protected:
void Shutdown();
// CValidationInterface
- void SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, int posInBlock);
- void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload);
+ void TransactionAddedToMempool(const CTransactionRef& tx) override;
+ void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected, const std::vector<CTransactionRef>& vtxConflicted) override;
+ void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) override;
+ void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override;
private:
CZMQNotificationInterface();
diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp
index caca1248a1..ab54e2bb8b 100644
--- a/src/zmq/zmqpublishnotifier.cpp
+++ b/src/zmq/zmqpublishnotifier.cpp
@@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "chain.h"
#include "chainparams.h"
#include "streams.h"
#include "zmqpublishnotifier.h"
@@ -30,6 +31,7 @@ static int zmq_send_multipart(void *sock, const void* data, size_t size, ...)
if (rc != 0)
{
zmqError("Unable to initialize ZMQ msg");
+ va_end(args);
return -1;
}
@@ -43,6 +45,7 @@ static int zmq_send_multipart(void *sock, const void* data, size_t size, ...)
{
zmqError("Unable to send ZMQ msg");
zmq_msg_close(&msg);
+ va_end(args);
return -1;
}
@@ -53,6 +56,7 @@ static int zmq_send_multipart(void *sock, const void* data, size_t size, ...)
size = va_arg(args, size_t);
}
+ va_end(args);
return 0;
}
@@ -86,7 +90,7 @@ bool CZMQAbstractPublishNotifier::Initialize(void *pcontext)
}
else
{
- LogPrint("zmq", "zmq: Reusing socket for address %s\n", address);
+ LogPrint(BCLog::ZMQ, "zmq: Reusing socket for address %s\n", address);
psocket = i->second->psocket;
mapPublishNotifiers.insert(std::make_pair(address, this));
@@ -116,13 +120,13 @@ void CZMQAbstractPublishNotifier::Shutdown()
if (count == 1)
{
- LogPrint("zmq", "Close socket at address %s\n", address);
+ LogPrint(BCLog::ZMQ, "Close socket at address %s\n", address);
int linger = 0;
zmq_setsockopt(psocket, ZMQ_LINGER, &linger, sizeof(linger));
zmq_close(psocket);
}
- psocket = 0;
+ psocket = nullptr;
}
bool CZMQAbstractPublishNotifier::SendMessage(const char *command, const void* data, size_t size)
@@ -132,7 +136,7 @@ bool CZMQAbstractPublishNotifier::SendMessage(const char *command, const void* d
/* send three parts, command & data & a LE 4byte sequence number */
unsigned char msgseq[sizeof(uint32_t)];
WriteLE32(&msgseq[0], nSequence);
- int rc = zmq_send_multipart(psocket, command, strlen(command), data, size, msgseq, (size_t)sizeof(uint32_t), (void*)0);
+ int rc = zmq_send_multipart(psocket, command, strlen(command), data, size, msgseq, (size_t)sizeof(uint32_t), nullptr);
if (rc == -1)
return false;
@@ -145,7 +149,7 @@ bool CZMQAbstractPublishNotifier::SendMessage(const char *command, const void* d
bool CZMQPublishHashBlockNotifier::NotifyBlock(const CBlockIndex *pindex)
{
uint256 hash = pindex->GetBlockHash();
- LogPrint("zmq", "zmq: Publish hashblock %s\n", hash.GetHex());
+ LogPrint(BCLog::ZMQ, "zmq: Publish hashblock %s\n", hash.GetHex());
char data[32];
for (unsigned int i = 0; i < 32; i++)
data[31 - i] = hash.begin()[i];
@@ -155,7 +159,7 @@ bool CZMQPublishHashBlockNotifier::NotifyBlock(const CBlockIndex *pindex)
bool CZMQPublishHashTransactionNotifier::NotifyTransaction(const CTransaction &transaction)
{
uint256 hash = transaction.GetHash();
- LogPrint("zmq", "zmq: Publish hashtx %s\n", hash.GetHex());
+ LogPrint(BCLog::ZMQ, "zmq: Publish hashtx %s\n", hash.GetHex());
char data[32];
for (unsigned int i = 0; i < 32; i++)
data[31 - i] = hash.begin()[i];
@@ -164,7 +168,7 @@ bool CZMQPublishHashTransactionNotifier::NotifyTransaction(const CTransaction &t
bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex)
{
- LogPrint("zmq", "zmq: Publish rawblock %s\n", pindex->GetBlockHash().GetHex());
+ LogPrint(BCLog::ZMQ, "zmq: Publish rawblock %s\n", pindex->GetBlockHash().GetHex());
const Consensus::Params& consensusParams = Params().GetConsensus();
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
@@ -186,7 +190,7 @@ bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex)
bool CZMQPublishRawTransactionNotifier::NotifyTransaction(const CTransaction &transaction)
{
uint256 hash = transaction.GetHash();
- LogPrint("zmq", "zmq: Publish rawtx %s\n", hash.GetHex());
+ LogPrint(BCLog::ZMQ, "zmq: Publish rawtx %s\n", hash.GetHex());
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
ss << transaction;
return SendMessage(MSG_RAWTX, &(*ss.begin()), ss.size());
diff --git a/src/zmq/zmqpublishnotifier.h b/src/zmq/zmqpublishnotifier.h
index bcbecf1bde..1790fe5698 100644
--- a/src/zmq/zmqpublishnotifier.h
+++ b/src/zmq/zmqpublishnotifier.h
@@ -24,32 +24,32 @@ public:
*/
bool SendMessage(const char *command, const void* data, size_t size);
- bool Initialize(void *pcontext);
- void Shutdown();
+ bool Initialize(void *pcontext) override;
+ void Shutdown() override;
};
class CZMQPublishHashBlockNotifier : public CZMQAbstractPublishNotifier
{
public:
- bool NotifyBlock(const CBlockIndex *pindex);
+ bool NotifyBlock(const CBlockIndex *pindex) override;
};
class CZMQPublishHashTransactionNotifier : public CZMQAbstractPublishNotifier
{
public:
- bool NotifyTransaction(const CTransaction &transaction);
+ bool NotifyTransaction(const CTransaction &transaction) override;
};
class CZMQPublishRawBlockNotifier : public CZMQAbstractPublishNotifier
{
public:
- bool NotifyBlock(const CBlockIndex *pindex);
+ bool NotifyBlock(const CBlockIndex *pindex) override;
};
class CZMQPublishRawTransactionNotifier : public CZMQAbstractPublishNotifier
{
public:
- bool NotifyTransaction(const CTransaction &transaction);
+ bool NotifyTransaction(const CTransaction &transaction) override;
};
#endif // BITCOIN_ZMQ_ZMQPUBLISHNOTIFIER_H